High-level types
The so-called high-level types are the language features introduced by TS to ensure the flexibility of the language. These features help us deal with complex and changing development scenarios.
Cross type
Cross typing is merging multiple types into one type. It contains all the required types of features. We mostly see the use of cross types in mixins and other places that don’t fit into the typical object-oriented model.
interface DogInterface {
run(): void;
}
interface CatInterface {
jump(): void;
}
let pet: DogInterface & CatInterface = { run() {}, jump(){}};Copy the code
The joint type
Union types indicate that a value can be one of several types. If a value is a union type, we can access only the members that are common to all types of that union type.
let a: number | string = "string"; // ok!
a = 1; // ok!
Copy the code
-
Literal union types
Literal type: an exact variable provided by TS
let b: 1 | "2" | true = 1; // ok! b = false; // error! Copy the code
-
Object association type
class Dog implements DogInterface { run() {} eat(){}}class Cat implements CatInterface { jump() {} eat(){}}enum Master { Boy, Girl, } function getPet(master: Master) { let pet = master === Master.Boy ? new Dog() : new Cat(); pet.eat(); // ok! pet.jump(); // error! return pet; } Copy the code
-
Distinguishable union types
A type protection method that combines union and literal types. If a type is a combination of multiple types, and there are common attributes between the types, we can create type-protected blocks based on this common attribute.
// Calculate the area of different figures interface Square { kind: "square"; size: number; } interface Rectangle { kind: "rectangle"; width: number; height: number; } function computedArea(shape: Square | Rectangle) { switch (shape.kind) { case "square": return shape.size * shape.size; case "rectangle": returnshape.width * shape.height; }}Copy the code
At this point, I want to add a circle, there will be a hidden danger.
interface Circle { kind: "circle"; r: number; } function computedArea(shape: Square | Rectangle | Circle) {... } computedArea({kind: "circle".r: 1 }); // undefinded Copy the code
There is no error at this point. There are two constraint schemes:
- Specify an explicit return value type
type Shape = Square | Rectangle | Circle; function computedArea(shape: Shape) :number { switch (shape.kind) { case "square": return shape.size * shape.size; case "rectangle": return shape.width * shape.height; case "circle": return Math.PI * shape.r ** 2; }}Copy the code
- using
never
typefunction computedArea(shape: Shape) { switch (shape.kind) { case "square": return shape.size * shape.size; case "rectangle": return shape.width * shape.height; case "circle": return Math.PI * shape.r ** 2; default: return ((e: never) = > { throw new Error(e); })(shape); }}Copy the code
check
shape
Whether it isnever
Type; whencase
When it’s completely covered,shape
是never
Type; Otherwise, you need to complete the branch.
- Specify an explicit return value type
The index type
A common Javascript pattern is to pick a subset of properties from an object.
let Obj = {
a: 1.b: 2.c: 3.d: 4};function getValues(obj: any, keys: string[]) {
return keys.map((key) = > obj[key]);
}
getValues(Obj, ["a"."b"]);
getValues(Obj, ["e"."f"]);
Copy the code
How do we constrain keys to be an index in obj?
interface Obj {
a: number;
b: number;
c: number;
d: number;
}
let obj: Obj = {
a: 1.b: 2.c: 3.d: 4};function getValues<T.K extends keyof T> (obj: T, keys: K[]) :T[K] []{
return keys.map((key) = > obj[key]);
}
getValues(obj, ["a"."b"]);
Copy the code
keyof T
: index type query operator
For any type T, the result of keyof T is the union of known public attribute names on T.
interface Obj { a: number; b: number; c: number; d: number; } let objProps: keyof Obj; // "a" | "b" | "c" | "d" Copy the code
T[K]
: index access operator
In this case, type syntax mirrors expression syntax.
let type: Obj["a"]; // number Copy the code
Mapping type
Typescript provides a way to create new types from old types.
interface Flags {
option1: boolean;
option2: boolean;
}
type ReadonlyFlags = Readonly<Flags>;
/* type ReadonlyFlags = { readonly option1: boolean; readonly option2: boolean; } * /
/** * lib.es5.d.ts * Make all properties in T readonly type Readonly
= { readonly [P in keyof T]: T[P]; }; * /
Copy the code
type PartialFlags = Partial<Flags>;
/* type PartialFlags = { option1? : boolean | undefined; option2? : boolean | undefined; } * /
Copy the code
type PickFlags = Pick<Flags, "option1">;
/* type PickFlags = { option1: boolean; } * /
type PickFlags = Pick<Flags, "option1" | "option2">;
Copy the code
Readonly, Partial, and Pick are homomorphic, but Record is not. Because Record does not require an input type to copy properties, it is not a homomorphism:
type twoStringProps = Record<"prop1" | "prop2".string>;
/* type twoStringProps = { prop1: string; prop2: string; } * /
Copy the code
Conditions in the
TypeScript 2.8 introduces conditional types, which can represent non-uniform types.
T extends U ? X : Y
Type X if T can be assigned to U, Y otherwise.
type TypeName<T> = T extends string
? "string"
: T extends number
? "number"
: "object";
Copy the code
-
Exclude \ Extract \ NotNullable
type T1 = Exclude<"a" | "b" | "c"."a" | "e">; // Exclude<"a", "a" | "e"> | Exclude<"b", "a" | "e"> | Exclude<"c", "a" | "e"> // never | "b" | "c" // "b" | "c" type T2 = Extract<"a" | "b" | "c"."a" | "e">; // T2 = "a" type T3 = NotNullable<number | string | null>; // type T3 = string | number Copy the code
-
Type inference in conditional Types: ReturnType is now in the extends substatement of conditional types, allowing the infer statement to introduce a type variable to be inferred.
type ReturnType<T> = T extends(... args:any[]) => infer R ? R : any; type T4 = ReturnType<() = > number>; Copy the code
The official implementation
/**
* Make all properties in T optional
*/
type Partial<T> = {
[P inkeyof T]? : T[P]; };/**
* Make all properties in T required
*/
type Required<T> = {
[P inkeyof T]-? : T[P]; };/**
* Make all properties in T readonly
*/
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
/**
* From T, pick a set of properties whose keys are in the union K
*/
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
/**
* Construct a type with a set of properties K of type T
*/
type Record<K extends keyof any, T> = {
[P in K]: T;
};
/**
* Exclude from T those types that are assignable to U
*/
type Exclude<T, U> = T extends U ? never : T;
/**
* Extract from T those types that are assignable to U
*/
type Extract<T, U> = T extends U ? T : never;
/**
* Construct a type with the properties of T except for those in type K.
*/
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
/**
* Exclude null and undefined from T
*/
type NonNullable<T> = T extends null | undefined ? never : T;
/**
* Obtain the parameters of a function type in a tuple
*/
type Parameters<T extends(... args:any) = >any> = T extends(... args: infer P) =>any ? P : never;
/**
* Obtain the parameters of a constructor function type in a tuple
*/
type ConstructorParameters<T extends new(... args:any) = >any> = T extends new(... args: infer P) =>any ? P : never;
/**
* Obtain the return type of a function type
*/
type ReturnType<T extends(... args:any) = >any> = T extends(... args:any) => infer R ? R : any;
/**
* Obtain the return type of a constructor function type
*/
type InstanceType<T extends new(... args:any) = >any> = T extends new(... args:any) => infer R ? R : any;
/**
* Convert string literal type to uppercase
*/
type Uppercase<S extends string> = intrinsic;
/**
* Convert string literal type to lowercase
*/
type Lowercase<S extends string> = intrinsic;
/**
* Convert first character of string literal type to uppercase
*/
type Capitalize<S extends string> = intrinsic;
/**
* Convert first character of string literal type to lowercase
*/
type Uncapitalize<S extends string> = intrinsic;
Copy the code
The basic TypeScript family
- Hello TypeScript (01) — Environment scaffolding
- Hello Typescript (02) — Enum types
- Hello Typescript (03) — Object type interface
- Hello Typescript (04) — function-type interfaces, mixed-type interfaces, class interfaces
- Hello Typescript (05) — functions
- Hello Typescript (06) — Classes
- Hello Typescript (07) — The relationship between classes and interfaces
- Hello Typescript (08) — Generic
- Hello Typescript (09) — Type inference, type compatibility, type protection
- Hello Typescript (10) — Cross type, union type, index type, map type, conditional type