关键词

  • 联合类型(Unions)
  • 泛型(Generics)
  • 结构类型、鸭子类型(Structural)
  • 单元类型(Unit)
  • 命名类型(Named)
  • 类型别名(Type Alias)
  • 上下文类型(Contextual)
  • 类型推断(Type Inference)
  • 类型参数(Type Parameters)
  • 高级类型(Higher-kinded)
  • 后置类型标注(Postfix Annotation)
  • 映射类型(Mapped Type)
  • 类型断言(Type Assertion)

书单

特性

Intersections

  1. // @refer: https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-func.html#intersections
  2. // Intersections
  3. // In addition to unions, TypeScript also has intersections:
  4. type Combined = { a: number } & { b: string };
  5. type Conflicting = { a: number } & { a: string };
  6. // Combined has two properties, a and b, just as if they had been written as one object literal type. Intersection and union are recursive in case of conflicts, so Conflicting.a: number & string.

Type Widen

  1. // @refer: https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-func.html#unit-types
  2. declare function pad(s: string, n: number, direction: "left" | "right"): string;
  3. pad("hi", 10, "left");
  4. let s = "right";
  5. pad("hi", 10, s); // error: 'string' is not assignable to '"left" | "right"'
  6. // Argument of type 'string' is not assignable to parameter of type '"left" | "right"'.
  7. let s: "left" | "right" = "right";
  8. pad("hi", 10, s);
  9. // Working around the problem with a type annotation for s, but that in turn prevents assignments to s of variables that are not of type "left" | "right".

Weird Contextual typing

  1. // @refer: https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-func.html#contextual-typing
  2. declare function map<T, U>(f: (t: T) => U, ts: T[]): U[];
  3. let sns = map((n) => n.toString(), [1, 2, 3]);
  4. // inference will work in any order, but intellisense will only work left-to-right, so TypeScript prefers to declare map with the array first:
  5. declare function map<T, U>(ts: T[], f: (t: T) => U): U[];

newtype

  1. // @refer: https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-func.html#type-aliases
  2. type FString = string & { __compileTimeOnly: any };
  3. // An FString is just like a normal string, except that the compiler thinks it has a property named __compileTimeOnly that doesn’t actually exist. This means that FString can still be assigned to string, but not the other way round.

Use Type Parameters when necessary

// TypeScript can usually infer type arguments from a call based on the type of the arguments, so type arguments are usually not needed.

// Because TypeScript is structural, it doesn’t need type parameters as much as nominal systems. Specifically, they are not needed to make a function polymorphic. Type parameters should only be used to propagate type information, such as constraining parameters to be the same type:

function length<T extends ArrayLike<unknown>>(t: T): number {}
function length(t: ArrayLike<unknown>): number {}

// In the first length, T is not necessary; notice that it’s only referenced once, so it’s not being used to constrain the type of the return value or other parameters.

Avoid Point-free

Point-free programming — heavy use of currying and function composition — is possible in JavaScript, but can be verbose. In TypeScript, type inference often fails for point-free programs, so you’ll end up specifying type parameters instead of value parameters. The result is so verbose that it’s usually better to avoid point-free programming.

Type & Value & Namespace

Deep Dive | Declaration Files