The author is also looking for a job after being laid off recently. If everyone thinks the article is good, I hope to provide an opportunity for referral.
ts basic knowledge review
https://juejin.cn/post/6844903981227966471#heading-79
😊 Access modifier in ts
- public, anywhere
- private, can only be accessed inside the class
- protected, can be accessed inside the class and in subclasses
- readonly, the attribute is set to read-only
😊 The difference between const and readonly
- const is used for variables, readonly is used for attributes
- const is checked at runtime, readonly is checked at compile time
Use const variables to save the array, you can use push, pop and other methods. But if you use
ReadonlyArray<number>
, you cannot use push, pop and other methods.😊 The difference between enumeration and constant enumeration (const enumeration)
- Enumeration will be compiled into an object when compiled, can be used as an object
- const enumeration will be deleted during ts compilation to avoid additional performance overhead
// 普通枚举
enum Witcher {
Ciri = 'Queen',
Geralt = 'Geralt of Rivia'
}
function getGeraltMessage(arg: {[key: string]: string}): string {
return arg.Geralt
}
getGeraltMessage(Witcher) // Geralt of Rivia
// const枚举
const enum Witcher {
Ciri = 'Queen',
Geralt = 'Geralt of Rivia'
}
const witchers: Witcher[] = [Witcher.Ciri, Witcher.Geralt]
// 编译后
// const witchers = ['Queen', 'Geralt of Rivia'
😊 Can interface in ts declare Function/Array/Class?
// 函数类型
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
let result = source.search(subString);
return result > -1;
}
// Array
interface StringArray {
[index: number]: string;
}
let myArray: StringArray;
myArray = ["Bob", "Fred"];
// Class, constructor存在于类的静态部分,所以不会检查
interface ClockInterface {
currentTime: Date;
setTime(d: Date);
}
class Clock implements ClockInterface {
currentTime: Date;
setTime(d: Date) {
this.currentTime = d;
}
constructor(h: number, m: number) { }
}
What is the difference between this in ts and this in js?
Don't understand
😊 How to enumerate union type keys in ts?
type Name = { name: string }
type Age = { age: number }
type Union = Name | Age
type UnionKey<P> = P extends infer P ? keyof P : never
type T = UnionKey<Union>
😊 What do the symbols such as ?., ??, !., _, ** in ts mean?
- ?. Optional chain
- ?? ?? Similar to short-circuit or, ?? avoids some unexpected situations. 0, NaN and "", false are regarded as false values. Only undefind and null are regarded as false values.
- !. Add! After the variable name, you can assert that undefined and null types are excluded
- _, Declares that the function will be passed a parameter, but you don’t care about it
- ** Exponentiation
- !:, assign this variable later, ts don’t worry
// ??
let x = foo ?? bar();
// 等价于
let x = foo !== null && foo !== undefined ? foo : bar();
// !.
let a: string | null | undefined
a.length // error
a!.length // ok
😊 What are anti-variation, double-variation, covariance and contravariance?
- Covariant, TS object compatibility is covariant, parent class <= child class, it is possible. Subcategory <= Parent category, error.
- Contravariant contravariant, disable
strictFunctionTypes
compilation, the function parameter type is contravariant, and the parent class <= the child class is an error. Subclass <= parent class, it is possible. Bivariant is two-way covariant. By default, the type of function parameter is two-way covariant. Parent category <= child category, it is possible. Subclass <= parent class, it is possible.
😊 Can the interface with the same name or the interface and class with the same name be combined in ts?
- interface will merge
- class cannot be merged
😊 How to make the ts project introduce and identify the npm library package compiled to js?
npm install @types/xxxx
Add description file yourself
😊 How does ts automatically generate declaration files for library packages?
You can configure tsconfig.json
file declaration
and outDir
- declaration: true, the declaration file will be automatically generated
- outDir:'', specify the directory
😊 What is generic
Generics are used to create reusable components, a component can support multiple types of data. In this way, users can use components with their own data types. simply said, "Generic is to treat the type as a parameter".
😊 -?, what does -readonly mean
Used to delete modifiers
type A = {
a: string;
b: number;
}
type B = {
[K in keyof A]?: A[K]
}
type C = {
[K in keyof B]-?: B[K]
}
type D = {
readonly [K in keyof A]: A[K]
}
type E = {
-readonly [K in keyof A]: A[K]
}
😊 TS is compatible based on structure type
Typescript's type compatibility is based on structure, not nominal. The following code is completely ok in ts, but it will throw an error in nominal-based languages such as java.
interface Named { name: string }
class Person {
name: string
}
let p: Named
// ok
p = new Person()
😊 const assertion
const assertion, typescript will add its own literal type to the variable
- Object literal attributes, get readonly attributes, and become read-only attributes
- Array literal becomes readonly tuple
- Literal types cannot be extended (for example, from hello type to string type)
// type '"hello"'
let x = "hello" as const
// type 'readonly [10, 20]'
let y = [10, 20] as const
// type '{ readonly text: "hello" }'
let z = { text: "hello" } as const
😊 The difference between type and interface
- Type aliases can introduce names for any type. Such as basic types, union types, etc.
- Type alias does not support inheritance
- Type alias does not create a real name
- Type aliases cannot be implemented (implements), and interfaces can be implemented by derived classes
- Compiler will throw an error when the type alias has the same name, and merge when the interface has the same name
😊 The difference between implements and extends
- extends, the subclass will inherit all the properties and methods of the parent class.
implements, the class using the implements keyword will need to implement all the properties and methods of the class that needs to be implemented.
😊 The difference between enumeration and object
- Enumeration can get the value of the enumeration by the name of the enumeration. The name of the enumeration can also be obtained through the value of the enumeration.
- Object can only get value through key
- In the case of digital enumeration without specifying an initial value, the enumeration value will increase from 0.
- Although at runtime, the enumeration is a real object. But the behavior when using keyof is inconsistent with ordinary objects. You must use keyof typeof to get all the attribute names enumerated.
😊 The difference between never and void
- never, never represents a type that never exists. For example, a function always throws an error without returning a value. Or there is an endless loop inside a function, and there will never be a return value. The return value of the function is the never type.
- void, the return value of the function that does not show the return value is void type. If a variable is of void type, it can only be assigned undefined or null.
the difference between unknown and any
The unknown type is similar to the any type. The difference with the any type is. The unknown type can accept any type assignment, but the unknown type must be asserted before assigning to other types
😊 How to extend type in window
declare global {
interface Window {
myCustomFn: () => void;
}
}
Complex type derivation problem
🤔 implement UnionToIntersection<T>
type A = UnionToIntersection<{a: string} | {b: string} | {c: string}>
// {a: string} & {b: string} & {c: string}
// 实现UnionToIntersection<T>
type UnionToIntersection<U> =
(U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never
// https://stackoverflow.com/questions/50374908/transform-union-type-to-intersection-type
// https://jkchao.github.io/typescript-book-chinese/tips/infer.html#%E4%B8%80%E4%BA%9B%E7%94%A8%E4%BE%8B
😊 implement ToNumber<T>
type A = ToNumber<'1'> // 1
type B = ToNumber<'40'> // 40
type C = ToNumber<'0'> // 0
// 实现ToNumber
type ToNumber<T extends string, R extends any[] = []> =
T extends `${R['length']}` ? R['length'] : ToNumber<T, [1, ...R]>;
😊 implement Add<A, B>
type A = Add<1, 2> // 3
type B = Add<0, 0> // 0
// 实现ADD
type NumberToArray<T, R extends any[]> = T extends R['length'] ? R : NumberToArray<T, [1, ...R]>
type Add<T, R> = [...NumberToArray<T, []>, ...NumberToArray<R, []>]['length']
😊 implement SmallerThan<A, B>
type A = SmallerThan<0, 1> // true
type B = SmallerThan<1, 0> // false
type C = SmallerThan<10, 9> // false
// 实现SmallerThan
type SmallerThan<N extends number, M extends number, L extends any[] = [], R extends any[] = []> =
N extends L['length'] ?
M extends R['length'] ? false : true
:
M extends R['length'] ? false : SmallerThan<N, M, [1, ...L], [1, ...R]>;
😊 implement LargerThan<A, B>
type A = LargerThan<0, 1> // false
type B = LargerThan<1, 0> // true
type C = LargerThan<10, 9> // true
// 实现LargerThan
type LargerThan<N extends number, M extends number, L extends any[] = [], R extends any[] = []> =
N extends L['length'] ?
false : M extends R['length'] ?
true : LargerThan<N, M, [1, ...L], [1, ...R]>;
😊 implement IsAny<T>
type A = IsAny<string> // false
type B = IsAny<any> // true
type C = IsAny<unknown> // false
type D = IsAny<never> // false
// 实现IsAny
type IsAny<T> = true extends (T extends never ? true : false) ?
false extends (T extends never ? true : false) ?
true
:
false
:
false;
// 更简单的实现
type IsAny<T> = 0 extends (T & 1) ? true : false;
😊 implement Filter<T, A>
type A = Filter<[1,'BFE', 2, true, 'dev'], number> // [1, 2]
type B = Filter<[1,'BFE', 2, true, 'dev'], string> // ['BFE', 'dev']
type C = Filter<[1,'BFE', 2, any, 'dev'], string> // ['BFE', any, 'dev']
// 实现Filter
type Filter<T extends any[], A, N extends any[] = []> =
T extends [infer P, ...infer Q] ?
0 extends (P & 1) ? Filter<Q, A, [...N, P]> :
P extends A ? Filter<Q, A, [...N, P]> : Filter<Q, A, N>
: N;
😊 implement TupleToString<T>
type A = TupleToString<['a']> // 'a'
type B = TupleToString<['B', 'F', 'E']> // 'BFE'
type C = TupleToString<[]> // ''
// 实现TupleToString
type TupleToString<T extends any[], S extends string = '', A extends any[] = []> =
A['length'] extends T['length'] ? S : TupleToString<T, `${S}${T[A['length']]}`, [1, ...A]>
😊 implement RepeatString<T, C>
type A = RepeatString<'a', 3> // 'aaa'
type B = RepeatString<'a', 0> // ''
// 实现RepeatString
type RepeatString<T extends string, C extends number, S extends string = '', A extends any[] = []> =
A['length'] extends C ? S : RepeatString<T, C, `${T}${S}`, [1, ...A]>
😊 implement Push<T, I>
type A = Push<[1,2,3], 4> // [1,2,3,4]
type B = Push<[1], 2> // [1, 2]
type C = Push<[], string> // [string]
// 实现Push
type Push<T extends any[], I> = T extends [...infer P] ? [...P, I] : [I]
😊 implement Flat<T>
type A = Flat<[1,2,3]> // [1,2,3]
type B = Flat<[1,[2,3], [4,[5,[6]]]]> // [1,2,3,4,5,6]
type C = Flat<[]> // []
// 实现Flat
type Flat<T extends any[]> =
T extends [infer P, ...infer Q] ?
P extends any[] ? [...Flat<P>, ...Flat<Q>] : [P, ...Flat<Q>]
: [];
😊 implement Shift<T>
type A = Shift<[1,2,3]> // [2,3]
type B = Shift<[1]> // []
type C = Shift<[]> // []
// 实现Shift
type Shift<T extends any[]> = T extends [infer P, ...infer Q] ? [...Q] : [];
😊 implement Repeat<T, C>
type A = Repeat<number, 3> // [number, number, number]
type B = Repeat<string, 2> // [string, string]
type C = Repeat<1, 1> // [1, 1]
type D = Repeat<0, 0> // []
// 实现Repeat
type Repeat<T, C, R extends any[] = []> =
R['length'] extends C ? R : Repeat<T, C, [...R, T]>
😊 implement ReverseTuple<T>
type A = ReverseTuple<[string, number, boolean]> // [boolean, number, string]
type B = ReverseTuple<[1,2,3]> // [3,2,1]
type C = ReverseTuple<[]> // []
// 实现ReverseTuple
type ReverseTuple<T extends any[], A extends any[] = []> =
T extends [...infer Q, infer P] ?
A['length'] extends T['length'] ? A : ReverseTuple<Q, [...A, P]>
: A;
😊 implement UnwrapPromise<T>
type A = UnwrapPromise<Promise<string>> // string
type B = UnwrapPromise<Promise<null>> // null
type C = UnwrapPromise<null> // Error
// 实现UnwrapPromise
type UnwrapPromise<T> = T extends Promise<infer P> ? P : Error;
😊 implement LengthOfString<T>
type A = LengthOfString<'BFE.dev'> // 7
type B = LengthOfString<''> // 0
// 实现LengthOfString
type LengthOfString<T extends string, A extends any[] = []> =
T extends `${infer P}${infer Q}` ? LengthOfString<Q, [1, ...A]> : A['length']
😊 implement StringToTuple<T>
type A = StringToTuple<'BFE.dev'> // ['B', 'F', 'E', '.', 'd', 'e','v']
type B = StringToTuple<''> // []
// 实现
type StringToTuple<T extends string, A extends any[] = []> =
T extends `${infer K}${infer P}` ? StringToTuple<P, [...A, K]> : A;
😊 implement LengthOfTuple<T>
type A = LengthOfTuple<['B', 'F', 'E']> // 3
type B = LengthOfTuple<[]> // 0
// 实现
type LengthOfTuple<T extends any[], R extends any[] = []> =
R['length'] extends T['length'] ? R['length'] : LengthOfTuple<T, [...R, 1]>
😊 implement LastItem<T>
type A = LastItem<[string, number, boolean]> // boolean
type B = LastItem<['B', 'F', 'E']> // 'E'
type C = LastItem<[]> // never
// 实现LastItem
type LastItem<T> = T extends [...infer P, infer Q] ? Q : never;
😊 implement FirstItem<T>
type A = FirstItem<[string, number, boolean]> // string
type B = FirstItem<['B', 'F', 'E']> // 'B'
// 实现FirstItem
type FirstItem<T> = T extends [infer P, ...infer Q] ? P : never;
😊 implement FirstChar<T>
type A = FirstChar<'BFE'> // 'B'
type B = FirstChar<'dev'> // 'd'
type C = FirstChar<''> // never
// 实现FirstChar
type FirstChar<T> = T extends `${infer P}${infer Q}` ? P : never;
😊 implement Pick<T, K>
type Foo = {
a: string
b: number
c: boolean
}
type A = MyPick<Foo, 'a' | 'b'> // {a: string, b: number}
type B = MyPick<Foo, 'c'> // {c: boolean}
type C = MyPick<Foo, 'd'> // Error
// 实现MyPick<T, K>
type MyPick<T, K extends keyof T> = {
[Key in K]: T[Key]
}
😊 implement Readonly<T>
type Foo = {
a: string
}
const a:Foo = {
a: 'BFE.dev',
}
a.a = 'bigfrontend.dev'
// OK
const b:MyReadonly<Foo> = {
a: 'BFE.dev'
}
b.a = 'bigfrontend.dev'
// Error
// 实现MyReadonly
type MyReadonly<T> = {
readonly [K in keyof T]: T[K]
}
😊 implement Record<K, V>
type Key = 'a' | 'b' | 'c'
const a: Record<Key, string> = {
a: 'BFE.dev',
b: 'BFE.dev',
c: 'BFE.dev'
}
a.a = 'bigfrontend.dev' // OK
a.b = 123 // Error
a.d = 'BFE.dev' // Error
type Foo = MyRecord<{a: string}, string> // Error
// 实现MyRecord
type MyRecord<K extends number | string | symbol, V> = {
[Key in K]: V
}
🤔️ implement Exclude
type Foo = 'a' | 'b' | 'c'
type A = MyExclude<Foo, 'a'> // 'b' | 'c'
type B = MyExclude<Foo, 'c'> // 'a' | 'b
type C = MyExclude<Foo, 'c' | 'd'> // 'a' | 'b'
type D = MyExclude<Foo, 'a' | 'b' | 'c'> // never
// 实现 MyExclude<T, K>
type MyExclude<T, K> = T extends K ? never : T;
🤔️ implement Extract<T, U>
type Foo = 'a' | 'b' | 'c'
type A = MyExtract<Foo, 'a'> // 'a'
type B = MyExtract<Foo, 'a' | 'b'> // 'a' | 'b'
type C = MyExtract<Foo, 'b' | 'c' | 'd' | 'e'> // 'b' | 'c'
type D = MyExtract<Foo, never> // never
// 实现MyExtract<T, U>
type MyExtract<T, U> = T extends U ? T : never
😊 implement Omit<T, K>
type Foo = {
a: string
b: number
c: boolean
}
type A = MyOmit<Foo, 'a' | 'b'> // {c: boolean}
type B = MyOmit<Foo, 'c'> // {a: string, b: number}
type C = MyOmit<Foo, 'c' | 'd'> // {a: string, b: number}
// 实现MyOmit
type MyOmit<T, K extends number | string | symbol> = {
[Key in Exclude<keyof T, K>]: T[Key]
}
type MyOmit<T, K extends number | string | symbol> = Pick<T, Exclude<keyof T, K>>
😊 implement NonNullable<T>
type Foo = 'a' | 'b' | null | undefined
type A = MyNonNullable<Foo> // 'a' | 'b'
// 实现NonNullable
type MyNonNullable<T> = T extends null | undefined ? never : T;
😊 implement Parameters<T>
type Foo = (a: string, b: number, c: boolean) => string
type A = MyParameters<Foo> // [a:string, b: number, c:boolean]
type B = A[0] // string
type C = MyParameters<{a: string}> // Error
// 实现MyParameters<T>
type MyParameters<T extends (...params: any[]) => any> =
T extends (...params: [...infer P]) => any ? P : never
😊 implement ConstructorParameters<T>
class Foo {
constructor (a: string, b: number, c: boolean) {}
}
type C = MyConstructorParameters<typeof Foo>
// [a: string, b: number, c: boolean]
// 实现MyConstructorParameters<T>
type MyConstructorParameters<T extends new (...params: any[]) => any> =
T extends new (...params: [...infer P]) => any ? P : never
😊 implement ReturnType<T>
type Foo = () => {a: string}
type A = MyReturnType<Foo> // {a: string}
// 实现MyReturnType<T>
type MyReturnType<T extends (...params: any[]) => any> =
T extends (...params: any[]) => infer P ? P : never;
😊 implement InstanceType<T>
class Foo {}
type A = MyInstanceType<typeof Foo> // Foo
type B = MyInstanceType<() => string> // Error
// 实现MyInstanceType<T>
type MyInstanceType<T extends new (...params: any[]) => any> =
T extends new (...params: any[]) => infer P ? P : never;
😊 implement ThisParameterType<T>
function Foo(this: {a: string}) {}
function Bar() {}
type A = MyThisParameterType<typeof Foo> // {a: string}
type B = MyThisParameterType<typeof Bar> // unknown
// 实现MyThisParameterType<T>
type MyThisParameterType<T extends (this: any, ...params: any[]) => any> =
T extends (this: infer P, ...params: any[]) => any ? P : unknown;
😊 implement TupleToUnion<T>
type Foo = [string, number, boolean]
type Bar = TupleToUnion<Foo> // string | number | boolean
// 实现TupleToUnion<T>
type TupleToUnion<T extends any[], R = T[0]> =
T extends [infer P, ...infer Q] ? TupleToUnion<Q, R | P> : R;
// 其他回答
type TupleToUnion<T extends any[]> = T[number]
😊 implement Partial<T>
type Foo = {
a: string
b: number
c: boolean
}
// below are all valid
const a: MyPartial<Foo> = {}
const b: MyPartial<Foo> = {
a: 'BFE.dev'
}
const c: MyPartial<Foo> = {
b: 123
}
const d: MyPartial<Foo> = {
b: 123,
c: true
}
const e: MyPartial<Foo> = {
a: 'BFE.dev',
b: 123,
c: true
}
// 实现MyPartial<T>
type MyPartial<T> = {
[K in keyof T]?: T[K]
}
😊 Required<T>
// all properties are optional
type Foo = {
a?: string
b?: number
c?: boolean
}
const a: MyRequired<Foo> = {}
// Error
const b: MyRequired<Foo> = {
a: 'BFE.dev'
}
// Error
const c: MyRequired<Foo> = {
b: 123
}
// Error
const d: MyRequired<Foo> = {
b: 123,
c: true
}
// Error
const e: MyRequired<Foo> = {
a: 'BFE.dev',
b: 123,
c: true
}
// valid
// 实现MyRequired<T>
type MyRequired<T> = {
[K in keyof T]-?: T[K]
}
😊 implement LastChar<T>
type A = LastChar<'BFE'> // 'E'
type B = LastChar<'dev'> // 'v'
type C = LastChar<''> // never
// 实现FirstChar<T>
type LastChar<T extends string, A extends string[] = []> =
T extends `${infer P}${infer Q}` ? LastChar<Q, [...A, P]> :
A extends [...infer L, infer R] ? R : never
;
😊 implement IsNever<T>
// https://stackoverflow.com/questions/53984650/typescript-never-type-inconsistently-matched-in-conditional-type
// https://www.typescriptlang.org/docs/handbook/advanced-types.html#v
type A = IsNever<never> // true
type B = IsNever<string> // false
type C = IsNever<undefined> // false
// 实现IsNever<T>
type IsNever<T> = [T] extends [never] ? true : false;
😊 implement KeysToUnion<T>
type A = KeyToUnion<{
a: string;
b: number;
c: symbol;
}>
// 'a' | 'b' | 'c'
// 实现KeyToUnion
type KeyToUnion<T> = {
[K in keyof T]: K;
}[keyof T]
😊 implement ValuesToUnion<T>
type A = ValuesToUnion<{
a: string;
b: number;
c: symbol;
}>
// string | number | symbol
// ValuesToUnion
type ValuesToUnion<T> = T[keyof T]
FindIndex<T, E>
https://bigfrontend.dev/zh/typescript/Search
type IsAny<T> = 0 extends (T & 1) ? true : false;
type IsNever<T> = [T] extends [never] ? true : false;
type TwoAny<A, B> = IsAny<A> extends IsAny<B> ? IsAny<A> : false;
type TwoNever<A, B> = IsNever<A> extends IsNever<B> ? IsNever<A> : false;
type SingleAny<A, B> = IsAny<A> extends true ? true : IsAny<B>
type SingleNever<A, B> = IsNever<A> extends true ? true : IsNever<B>
type FindIndex<T extends any[], E, A extends any[] = []> =
T extends [infer P, ...infer Q] ?
TwoAny<P, E> extends true ?
A['length']
:
TwoNever<P, E> extends true ?
A['length']
:
SingleAny<P, E> extends true ?
FindIndex<Q, E, [1, ...A]>
:
SingleNever<P, E> extends true ?
FindIndex<Q, E, [1, ...A]>
:
P extends E ? A['length'] : FindIndex<Q, E, [1, ...A]>
:
never
implement Trim<T>
type A = Trim<' BFE.dev'> // 'BFE'
type B = Trim<' BFE. dev '> // 'BFE. dev'
type C = Trim<' BFE . dev '> // 'BFE . dev'
type StringToTuple<T extends string, A extends any[] = []> =
T extends `${infer K}${infer P}` ? StringToTuple<P, [...A, K]> : A;
type TupleToString<T extends any[], S extends string = '', A extends any[] = []> =
A['length'] extends T['length'] ? S : TupleToString<T, `${S}${T[A['length']]}`, [1, ...A]>
type Trim<T extends string, A extends any[] = StringToTuple<T>> =
A extends [infer P, ...infer Q] ?
P extends ' ' ?
Trim<T, Q>
:
A extends [...infer M, infer N] ?
N extends ' ' ?
Trim<T, M>
:
TupleToString<A>
:
''
:
'';
There are more UnionToTuple
, IntersectionToUnion
?
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。