Author: ICBU Dongmo

Write at the front: welcome to Alibaba ICBU interactive & end technology front end team column, we will share quality front end technology articles with you, welcome to pay attention to & exchange yo!

Preamble: When writing typescript applications, we sometimes want to reuse or construct types of a particular structure that are hard to express from typescript with built-in types, interfaces, and classes.

keyof

In typescript we use the keyof keyword to extract the index tags of objects.

// obj is an object, and typeof gets its type keyof (Typeof obj)Copy the code

The string and number indexes of the object

For ES5, there is no doubt that an index in a hash dictionary can only be a string and a number;

// One simiple object with any type key-value
interface Foo {
    [k: string]: any
}

type TFOO = keyof Foo // string | number
Copy the code

The element index of an array has its own special meaning, but it is still of type number.

const a = [] type TA = keyof (typeof a) /** number | "length" | "toString" | "toLocaleString" | "pop" | "push" | "concat" | "join" | "reverse" | "shift" | "slice" | "sort" | "splice" | "unshift" | "indexOf" | "lastIndexOf" | ... * /Copy the code

Symbol index

Starting with ES6, javascript allows the use of Symbol as an object index

interface objWithSymbol {
    foo: string
    [Symbol.toStringTag]: any
}
type T_OBJ_WITH_SYM = keyof objWithSymbol // "foo"

const a_with_symkey = {
    [Symbol('#symA')]: 'bar'
}
type T_A = keyof typeof a_with_symkey // number | string
Copy the code

At the time of writing, typescript does not support extracting Symbol indexes using the keyof keyword, which is understandable because symbols are often not represented as “keys “. There is no other official way to directly extract an index of the Symbol type in an interface or object type. Symbol has no literal text. The guarantee of its uniqueness is the memory allocation at runtime, not the literal.

In typescript, writing like this violates a type constraint:

Const a = {} // lint: no property 'foo' on type '{}'. ts(2339) a.foo = 'bar'Copy the code

But that won’t:

const a = {}
a[Symbol('#symA')] = 'bar'
Copy the code

Note that Symbol is an index of an Object that does not enumerable: True. And for… In extraction. Similar to get access to an Object string | number type method of the index is the Object. The getOwnPropertyNames (); All Symbol in the access to an Object type Object. The index way getOwnPropertySymbols ();

Extract element types using any as the index

What do we do when we declare an array (of type String []) where all elements are of the same type (for example, string) and we want to get the types of the elements in the array for subsequent variable constraints?

const a: string[] = []
type ELE_A = string
Copy the code

For simple built-in types, we can of course simply declare, or simply declare a as ELE_A[]; And if so?

const a: {a: string, b: string, c: number}[] = []
Copy the code

We can of course declare ELE_A in advance, and then declare a to be ELE_A[]

What if that’s the case?

const a: {a: string, b: string, c: number}[] = []
const a1: {a: string, b: string}[] = []
const a2: {foo: string, c: string}[] = []
Copy the code

If you declare every variable in advance, it feels like writing C: declare first, call later. Using any can help us extract the elements, for example

const a: {a: string, b: string, c: number}[] = []
type T_A = (typeof a)[any]
const a1: {a: string, b: string}[] = []
type T_A1 = (typeof a1)[any]
const a2: {foo: string, c: string}[] = []
type T_A2 = (typeof a2)[any]
Copy the code

In this way, we don’t have to explicitly declare the types of array elements that are reused only once or twice. Instead, we declare variables first and then extract them.

Extract directly from an existing interface

For the following interface, what if I want to extract the type of the element in foo2 (which is an array)?

interface A {
    foo: {
       foo2: {
           foo3: string[]
       }[]
    }
}
Copy the code

Index directly from A to foo2, then extract its elements using any

type FOO2_ELE = A['foo']['foo2'][any]
Copy the code

❤️ Thank you for seeing the end ~

Alibaba international website (ICBU, Alibaba.com) is the world’s largest cross-border trade and service platform. We have new technical challenges all the time, enough interesting challenges to satisfy all your curiosity and thirst for knowledge, and well-known foreign partners (Google & OpenSky).

If you want to come to ICBU to develop the front end with me, please send your resume to [email protected] and we will respond to your interview arrangement quickly. : -)