This is the first in a series on playing with TypeScript tool types. This series is about learning about TypeScript tool types. If there are any mistakes, please point them out at 🙇

Through this series, we hope to achieve the following objectives as far as possible:

  • Understand the implementation mechanism for each tool type from a source code perspective
  • Walk through a simple example or two to understand the basic usage of each tool type
  • At the same time deepen theTypeScriptThe understanding of the
  • The final realization can be drawn from the actual work

Quick jump

  • Playing with TypeScript tool Types (Middle)
  • Playing with TypeScript tool Types (2)

1. Partial<Type>: optional

>> Source code interpretation

The source code for Partial

looks like this:

type Partial<T> = { [P in keyof T]? : T[P]; };Copy the code

There are four points to note here:

  • <T>: This is the target type, the type we are going to process. The type is uncertain, so we use genericsTsaid
  • [P in keyof T]:keyof TreturnTA type consisting of all the keys of a type,inCan follow the jsfor.. inTraverse to understand, follow upkeyofThere are more detailed instructions
  • ?: Optional, all attributes of the return type are converted to optional types
  • Returns a new type that is derived fromTAnd, andTThere’s one on the propertyInheritance relationshipsIn section 2, yesRequired<Type>This will be verified in the description of the

The Partial

Type returns a new Type that has the same properties as the target Type T, but all of the properties are optional.

>> Actual usage

Scenario Description: In actual business development, you often need to update a Partial or Partial data object. You can use Partial

.

interface DataModel { name: string age: number address: string } let store: DataModel = { name: '', age: 0, address: '' } function updateStore ( store: DataModel, payload: Partial<DataModel> ):DataModel { return { ... store, ... payload } } store = updateStore(store, { name: 'lpp', age: 18 })Copy the code

Try it yourself

> > added

Here’s an explanation for keyof, to understand it:

interface Person {
  name: string;
  age: number;
  location: string;
}

type K1 = keyof Person; // "name" | "age" | "location"
type K2 = keyof Person[];  // "length" | "push" | "pop" | "concat" | ...
type K3 = keyof { [x: string]: Person };  // string

const person: Person = {
  name: '',
  age: 0,
  location: ''
}

type k11 = keyof typeof person; // "name" | "age" | "location"
Copy the code

Reference 1: Official documentation

What does “keyof Typeof” mean in TypeScript?


2. Required<Type>Necessary:

>> Source code interpretation

type Required<T> = { [P in keyof T]-? : T[P]; };Copy the code

The purpose of this type is to make all attributes of type T optional.

The source code here uses a -? To label the attribute as a required attribute, so this -? Is it necessary? Because what we understand as an optional property is using? Well marked is optional if we put -? If removed, why can’t the effect of Required be achieved? Let’s start by writing a MyRequired

as follows:

type MyRequired<T> = { [P in keyof T]: T[P]; }; interface Props { a? : number; b? : string; } const obj: MyRequired<Props> = { a: 5 };Copy the code

Try it yourself

The above code is type-free. Why? Because if it were just [P in keyof T], the property in P would retain its own optionality in T. That is, if it was required before, it is still required in the new type, and it is the same if it is optional. It’s kind of like an “inheritance relationship.” So use -? To clear the optional implementation Required. Of course, +? Partial

= Partial

The plus of theta can be omitted.

>> Actual usage

Required

converts all attributes of type T passed in as Required. So the most common use is to do conversions like this, but if you just want to make certain attributes of type T mandatory and return them as a new type:

interface Props { a? : string b? : string c? : String} / / retain only b and c properties and to mandatory type NewProps1 = Required < Pick < Props, 'b' | 'c' > > / / need to keep all attributes of the Props, but b, C will need to fill in the type NewProps2 = Partial < Props > & Required < Pick < Props, 'b' | 'c' > > const obj: NewProps2 = {b: '1', c: '2'}Copy the code

Try it yourself


3. ReadOnly<Type>: read only

>> Source code interpretation

type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};
Copy the code

Set the property contained in type T to readonly and return a new type. Readonly, as the name implies, is read-only and cannot be modified after initialization. This type can be used in conjunction with javascript’s const keyword to reference the value of a type attribute as a constant.

One limitation of this type is that the child can only be set to read-only. If the child is also a reference type, this does not apply to the child. Is there any way to recursively set all references to be read-only? If you have this way please leave me a message, thank you 🧎♂️

>> Actual usage

interface Person { name: string age: number } const person: Readonly<Person> = { name: 'lpp', age: 18 } person.age = 20; // Cannot be assigned to "age" because it is read-only. ts(2540)Copy the code

Without readOnly, in javascript, assigning a const variable to a unique reference type, such as an object, allows you to change the value of the property, but not the reference stored in the variable. To make the value of an object’s property immutable, You can use object.freeze in javascript.

function freeze<Type>(obj: Type): Readonly<Type>;
Copy the code

4. Record<Keys, Type>Record:

The utility Type constructs a Type whose key Type is Keys and value Type is Type.

>> Source code interpretation

type Record<K extends keyof any, T> = {
    [P in K]: T;
};
Copy the code

Here we see that the type definition for K uses keyof any. Here keyof any equivalent to the string | number | symbol, as shown below:

type a = keyof any; / / equivalent to type a = string | number | symbol;Copy the code

>> Actual usage

Type Obj1 = Record<string, String > / / based on other types of generating new type type FruitTypes = 'apple' | 'banana' | 'pear' interface FruitInfo {name: FruitTypes price: number } type Fruits = Partial<Record<FruitTypes, FruitInfo>> const fruits: Fruits = { apple: { name: 'apple', price: 10}}Copy the code

Try it yourself


5. Pick<Type, Keys>: pick

From Type Type, select a set of attributes to form a new Type. This set of attributes is qualified by Keys, which are strings or combinations of strings.

>> Source code interpretation

type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};
Copy the code

K extends keyof T, which means K needs to be a subset of keyof T. The key of the returned type should be [P in K] and the value type should be T[P].

>> Actual usage

Interface Person {name: string age: number id: string} / / children have no id type Toddler = Pick < Person, 'name' | 'age >Copy the code

6. Omit<Type, Keys>: ignore

Construct a Type that contains the attributes of Type Type except Keys. Keys is a string or union of strings.

>> Source code interpretation

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
type Exclude<T, U> = T extends U ? never : T;
Copy the code

Since Omit relies on Exclude, the source code of the Exclude type is posted here. **Exclude

excludes all types that can be assigned to U from T. ** Exclude is not implemented here, just need to know the function. Therefore, Omit

can be regarded as a counter selection, and Omit the attributes of T that are not included in K, and then use Pick to implement Omit

,>

>> Actual usage

interface Person { name: string age: number id: string work: string address: string girlFriend: Number} // Omit Person = Person, 'work'> // Omit Person = Person, Type PersonNoGirlFriend =Omit<Person, 'girlFriend'>Copy the code

> > exercises

How to implement a tool type SelectRequired

to achieve the following:
,>

interface Props { a? : string b? : string c? : string d: string } type NewProps = SelectRequired<Props, 'b' | 'c'>; // { a? : string, b: string, c: string, d: string }Copy the code

The answer point is here