Skip to content
0

TypeScript

TS 相关

standard-schema ---> TS Validate 标准接口

由如下 TS 定义组成:

standard-schema
/** The Standard Schema interface. */
export interface StandardSchemaV1<Input = unknown, Output = Input> {
  /** The Standard Schema properties. */
  readonly '~standard': StandardSchemaV1.Props<Input, Output>;
}

export declare namespace StandardSchemaV1 {
  /** The Standard Schema properties interface. */
  export interface Props<Input = unknown, Output = Input> {
    /** The version number of the standard. */
    readonly version: 1;
    /** The vendor name of the schema library. */
    readonly vendor: string;
    /** Validates unknown input values. */
    readonly validate: (
      value: unknown
    ) => Result<Output> | Promise<Result<Output>>;
    /** Inferred types associated with the schema. */
    readonly types?: Types<Input, Output> | undefined;
  }

  /** The result interface of the validate function. */
  export type Result<Output> = SuccessResult<Output> | FailureResult;

  /** The result interface if validation succeeds. */
  export interface SuccessResult<Output> {
    /** The typed output value. */
    readonly value: Output;
    /** The non-existent issues. */
    readonly issues?: undefined;
  }

  /** The result interface if validation fails. */
  export interface FailureResult {
    /** The issues of failed validation. */
    readonly issues: ReadonlyArray<Issue>;
  }

  /** The issue interface of the failure output. */
  export interface Issue {
    /** The error message of the issue. */
    readonly message: string;
    /** The path of the issue, if any. */
    readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
  }

  /** The path segment interface of the issue. */
  export interface PathSegment {
    /** The key representing a path segment. */
    readonly key: PropertyKey;
  }

  /** The Standard Schema types interface. */
  export interface Types<Input = unknown, Output = Input> {
    /** The input type of the schema. */
    readonly input: Input;
    /** The output type of the schema. */
    readonly output: Output;
  }

  /** Infers the input type of a Standard Schema. */
  export type InferInput<Schema extends StandardSchemaV1> = NonNullable<
    Schema['~standard']['types']
  >['input'];

  /** Infers the output type of a Standard Schema. */
  export type InferOutput<Schema extends StandardSchemaV1> = NonNullable<
    Schema['~standard']['types']
  >['output'];
}

effect ---> 构建健壮的 TS 应用

Effect 由多个包组成,这些包协同工作以帮助构建健壮的 TypeScript 应用程序。核心包 effect 充当框架的基础,提供用于管理副作用、确保类型安全和支持并发的基元。

import { Effect } from "effect"
// type Effect<Success, Error, Requirements> = (
//   context: Context<Requirements>
// ) => Error | Success

const divide = (a: number, b: number): Effect.Effect<number, Error> =>
  b === 0
    ? Effect.fail(new Error("Cannot divide by zero"))
    : Effect.succeed(a / b)

tsd ---> TS 类型运行时验证库

虽然 vitest 等库也有类似的功能,但是当仅仅想验证 TS 类型的作为测试的时候,可以使用这个库

$ [npx] tsd [path]

测试文件使用 *.test-d.ts 结尾

import {expectType} from 'tsd';
import concat from '.';

expectType<string>(concat('foo', 'bar'));
expectType<string>(concat(1, 2));

xterm ---> 终端组件

如果想在 Web 页面中实现一个终端,xterm 绝对是一个不错的选择

import { Terminal } from 'xterm';

const terminal = new Terminal();

terminal.open(document.getElementById('terminal'));
terminal.write('Hello from \x1B[1;3;31mxterm.js\x1B[0m $ ')

ts-essentials ---> 常用的 TS 泛型库

包含了常用的泛型类型方法:

memoize ---> 缓存函数结果

适用于包裹某些耗时的,并且当参数相同时,返回值相同的函数,避免重复计算

import memoize from 'memoize';

let index = 0;
const counter = () => ++index;
const memoized = memoize(counter);

memoized('foo');
//=> 1

// Cached as it's the same argument
memoized('foo');
//=> 1

也有异步函数的版本 sindresorhus/p-memoize

typedoc ---> ts类型文档生成器

为你的导出的ts类型生成文档

$ npm install typedoc
$ typedoc src/index.ts

typescript-json ---> JSON快速序列化和类型检查

import TSON from "typescript-json";

// RUNTIME TYPE CHECKERS
TSON.assertType<T>(input); // throws exception
TSON.is<T>(input); // returns boolean value
TSON.validate<T>(input); // archives all type errors

// STRINGIFY
TSON.stringify<T>(input); // 5x faster JSON.stringify()

// APPENDIX FUNCTIONS
TSON.application<[T, U, V], "swagger">(); // JSON schema application generator
TSON.create<T>(input); // 2x faster object creator (only one-time construction)

type-fest ---> ts 类型库

import type {Except} from 'type-fest';

type Foo = {
	unicorn: string;
	rainbow: boolean;
};

type FooWithoutRainbow = Except<Foo, 'rainbow'>;
//=> {unicorn: string}

joi ---> 精确地描述数据与预期的差异

通过配置标准数据的预定格式,给出与测试数据不一致的描述

import Joi from 'joi'

const schema = Joi.object({
  username: Joi.string().alphanum().min(3).max(30).required(),

  password: Joi.string().pattern(new RegExp('^[a-zA-Z0-9]{3,30}$')),

  repeat_password: Joi.ref('password'),

  access_token: [ Joi.string(), Joi.number()],

  birth_year: Joi.number().integer().min(1900).max(2013),

  email: Joi.string().email({ minDomainSegments: 2, tlds: { allow: ['com', 'net'] } })

}).with('username', 'birth_year')
  .xor('password', 'access_token')
  .with('password', 'repeat_password');


console.log(schema.validate({ username: 'abc', birth_year: 1994 }))
/*
{
  value: { username: 'abc', birth_year: 1994 },
  error: [Error [ValidationError]: "value" must contain at least one of [password, access_token]] {
    _original: { username: 'abc', birth_year: 1994 },
    details: [ [Object] ]
  }
}
*/

其他类似的库

LibraryMinified sizeGzipped sizeCompression rateStars
Superstruct11.5 kB3.4 kB70.43 %
io-ts20.5 kB5.2 kB74.63 %
Runtypes30.6 kB7.4 kB75.82 %
Valibot46.7 kB7.5 kB83.94 %
Yup40.08 kB12.4 kB69.06 %
Zod57 kB13.2 kB76.84 %
Ajv119.6 kB35.2 kB70.57 %
Joi151.1 kB43 kB71.54 %

trpc ---> 配合zod,提供端到端类型安全的API

$ npm install @trpc/server @trpc/client

importx ---> 在 NodeJs 运行时导入 Typescript 的统一工具

有很多方法可以做到在 JS 中导入 TS, importx 可以自动选择最合适的 loader 来导入,以便提供最合适的方式和最好的性能

const mod = await import('importx').then(x => x.import('./path/to/module.ts', import.meta.url))

内部集成的 loader:

import { tsImport } from 'tsx/esm/api'

const loaded = await tsImport('./file.ts', import.meta.url)
const jiti = require("jiti")(__filename);

jiti("./path/to/file.ts");
import { bundleRequire } from 'bundle-require'

const { mod } = await bundleRequire({
  filepath: './project/vite.config.ts',
})

Auto 模式下的识别流程图:

yup ---> 将类型检验带到运行时

import { object, string, number, date, InferType } from 'yup';

let userSchema = object({
  name: string().required(),
  age: number().required().positive().integer(),
  email: string().email(),
  website: string().url().nullable(),
  createdOn: date().default(() => new Date()),
});

// parse and assert validity
const user = await userSchema.validate(await fetchUser());

type User = InferType<typeof userSchema>;
/* {
  name: string;
  age: number;
  email?: string | undefined
  website?: string | null | undefined
  createdOn: Date
}*/

ts-pattern ---> TS 安全的条件匹配

import { match, P } from 'ts-pattern';

type Data =
  | { type: 'text'; content: string }
  | { type: 'img'; src: string };

type Result =
  | { type: 'ok'; data: Data }
  | { type: 'error'; error: Error };

const result: Result = ...;

const html = match(result)
  .with({ type: 'error' }, () => <p>Oups! An error occured</p>)
  .with({ type: 'ok', data: { type: 'text' } }, (res) => <p>{res.data.content}</p>)
  .with({ type: 'ok', data: { type: 'img', src: P.select() } }, (src) => <img src={src} />)
  .exhaustive();

untyped ---> 根据对象生成类型或MD

const defaultPlanet = {
  name: "earth",
  specs: {
    gravity: {
      $resolve: (val) => parseFloat(val),
      $default: "9.8",
    },
    moons: {
      $resolve: (val = ["moon"]) => [].concat(val),
      $schema: {
        title: "planet moons",
      },
    },
  },
};
import { resolveSchema, generateTypes } from "untyped";

const types = generateTypes(await resolveSchema(defaultPlanet));

console.log(types)
interface Untyped {
  /** @default "earth" */
  name: string;

  specs: {
    /** @default 9.8 */
    gravity: number;

    /**
     * planet moons
     * @default ["moon"]
     */
    moons: string[];
  };
}

ts-reset ---> 提高一些 JS API 的类型体验

  • 👍 .json (in fetch) and JSON.parse both return unknown
  • .filter(Boolean) behaves EXACTLY how you expect
  • 🥹 array.includes is widened to be more ergonomic
  • 🚀 And several more changes!
安装

$ npm i -D @total-typescript/ts-reset

使用
import "@total-typescript/ts-reset";

ts-morph ---> TS TYPE AST

Parse TS source code to ast. ts-ast-viewer here.

import { Project } from "ts-morph";

const project = new Project();
const sourceFile = project.createSourceFile('validate.ts', tsCode);
const tsTypeString = file.getTypeAlias(item.name) || file.getInterface(item.name) || file.getEnum(item.name)

string-ts ---> Strongly typed string functions

import { replace } from 'string-ts'

const str = 'hello-world'
const result = replace(str, '-', ' ')
//    ^ 'hello world'

Released under the MIT License.