In JS we can pass for… In iterates through all keys of an object{} and then performs some logical processing. Is there a similar function for iterating through interface{} in TS version 2.1 introduced this capability.

The result can only be assigned to a type, the simplest form of writing:

{ [ K in P ] : T }
Copy the code

Below, we give a detailed description of what K, P and T represent respectively.

Use map types to quickly create types

type Coord = {
    [K in 'x' | 'y'] :number;
};
/ / get
// type Coord = {
// x: number;
// y: number;
// }
Copy the code

The preference is to make sure that it executes a loop (which can be interpreted as similar to for… In effect), where P directly set to ‘x’ | ‘y’ type of a joint, and K is an identifier, it is mapped to the P type of each child. T is the data type, which we fixed directly to number, or any other complex type.

Since the t-value data type can be any value, even the value 1, we can set the data class to K itself:

type Coord = { [K in 'x' | 'y']: K };
Type Coord = {x: 'x'; y: 'y'; }
Copy the code

Replication using mapping types

type Item = {
    a: string
    b: number
    c: boolean
}

// a combined type of all attributes of Item
type ItemKeys = 'a' | 'b' | 'c';
// Can also be abbreviated as:
// type ItemKeys = keyof Item;

type Copy = { [K in ItemKeys]: Item[K] };
Type Copy = {a: string, b: number, c: Boolean};
Copy the code

The Copy type here is exactly the same as the declaration in Item, which can be abbreviated as:

type Item = { a: string, b: number, c: boolean };
type Copy = { [K in keyof Item]: Item[K] };
Type Copy = {a: string, b: number, c: Boolean};
Copy the code

Based on this property and the index access type, we can encapsulate a copy effect function type:

type Copy<P> = { [K in keyof P]: P[K] }

type Item = { a: string, b: number, c: boolean };
type ItemCopy = Copy<Item>;
Type ItemCopy = {a: string, b: number, c: Boolean};
Copy the code

The function type that generates the type

A function type that encapsulates a rapidly generated interface type based on this property:

type Create<P extends keyof any, T> = { [K in P]: T };

type Coord = Create<'x' | 'y'.number>;
Type Coord = {x: number, y: number};
Copy the code

If this looks familiar, you’ve seen or used the official preset advanced type Record

, and yes, they’re exactly the same.

The extends condition type here is used for the purpose of inheritance, where we pass in the union type. Since P must be assignable to string, we need to place some restrictions to ensure that the P received is a valid value.

One feature of keyof is that the type of keyof T is considered a subtype of string, number, and symbol. (more on keyof features later) based detection of keyof any, so the following uses will generate an error:

type Val = Create<true.boolean>;
// Error: Type 'true' does not satisfy the constraint 'string | number | symbol'.

type Val2 = Create<(a)= > void>;
// Error: Type '() => void' does not satisfy the constraint 'string | number | symbol'
Copy the code

Decorator for the mapping type

You can also use readonly or? To set the properties:

type Coord = {
    readonly [K in 'x' | 'y'] :number
};
/ / get
// type Coord = {
// readonly x: number;
// readonly y: number;
// };
Copy the code

Two decorators can also be used in combination:

type Coord = {
    readonly [K in 'x' | 'y']? :number;
};
/ / get
// type Coord = {
//  readonly x?: number;
//  readonly y?: number;
// };
Copy the code

However, there are limitations to removing decorators that already exist on attributes:

typeCoordOptional = { x? :number;
    readonly y: number;
};
type Coord = {
    [K in keyof CoordOptional]: number;
};
/ / get
// type Coord = {
//  x?: number;
// readonly y: number;
// };
Copy the code

For this reason, the community has improved it again in TS2.8 by adding – or + to the decorator:

typeCoordOptional = { x? :number;
    readonly y: number;
};
type Coord = {
    -readonly [K inkeyof CoordOptional] -? :number;
};
/ / get
// type Coord = {
// x: number;
// y: number;
// };

Copy the code