Summarize some places that have spent time on TypeScript
- 2021-12-05 05:17:39
- OfStack
Record some places where you spent time on ts.
(Spit a slot first: stackoverflow really has everything, Baidu really can't use it)
Pit
Compatibility misunderstandings of as assertions, such as "a" as "b", do not report errors.
The behavior of interface and type (I thought I wrote the wrong type when I first met, and I was forced):
type Type = {
key: "value"
}
interface Interface {
key: "value"
}
type It doesn't seem to make any difference. It's all true = Type extends Interface ? Type extends Interface ? true : false : false
type Pit point = {
[key: string]: Pit point
} | string
type Test <T> = T extends Pit point ? true : false
type This is true = Test <Type>
type This is false = Test <Interface>
There is an official explanation on github that such a pit was deliberately left. It is said that interface is extensible (automatic merge of the same name), so it is inconvenient to detect.
When using generics to implement the effect of function overloading, it is often necessary to use as to enforce assertions because generics do not have specific constraints in the implementation of functions.
// Almost this meaning, the following code is too lazy to actually test 🙃
//fns Is a functional index table, TFns Is the of the index table const Type
function Overload failure <T extends keyof TFns>(fn:T, params: Parameters<fns[T]>){
fns[fn](...params)// In the implementation, the union type will not shrink, so an error will be reported
// Errors should be like You cannot put a method 1 Pass the parameters of to the method 2 This
}
// However, when used externally, it is nothing to conform to the semantics of the type
Extension operators are not intuitive: the type [... string [], number] is intuitive when used (requiring an number element at the end of the array), but the type [... string [], null,... object [], number] does not, does not come in sequence, and does not report errors. The new version of ts adds a rule prohibiting continuous deconstruction, which directly prevents writing.
In fact, there is a solution here, but the written type is simply impossible to see (a few 10 lines, including a large number of extends as the type of if judgment), so the following paste code is not posted:
// Types required: [...number[], "middle-element", ...boolean[]]
// The above writing is invalid, just indicate what the following type code is used for (implementing the type constraint indicated above)
type Elem = number | boolean | "middle-element";
type Last<T extends any[]> = T extends [infer _]
? never
: T extends [...infer _, infer Tl]
? Tl
: never
type HandleEmpty<T extends any[], Data> = T['length'] extends 0 ? never : Data
type Validation<Params extends any[], Cache extends Elem[] = []> =
Params extends []
? Cache['length'] extends 0
? never
: Cache
: Params extends [infer Fst, ...infer Rest]
? Cache extends []
? Fst extends number
? HandleEmpty<Rest, Validation<Rest, [...Cache, Fst]>>
: never
: Fst extends number
? Last<Cache> extends number
? HandleEmpty<Rest, Validation<Rest, [...Cache, Fst]>>
: never
: Fst extends "middle-element"
? Last<Cache> extends number
? HandleEmpty<Rest, Validation<Rest, [...Cache, Fst]>>
: never
: "middle-element" extends Cache[number]
? Fst extends boolean
? Validation<Rest, [...Cache, Fst]>
: never
: never
: never
type IsNever<T> = [T] extends [never] ? true : false;
function check<
Params extends Elem[],
IsValid extends Validation<Params>
>(...arr: IsNever<IsValid> extends true ? [never] : [...Params]) {
return arr
}
const Normal = check(1, 'middle-element', false)
const Report an error = check(false, "middle-element", 2)
Advanced operation
Object name remapping:
//{ "new-a":any; "new-b":any }
type Remapping = {
[K in "a" | "b" as `new-${K}`]: any
}
Split of union type: Split of union type can be realized by using infer keyword.
//"a1"|"b2"
type Successful splitting <_Keys = keyof { a: 1, b: 2 }> = _Keys extends infer K ?
`${Extract<K, string>}${{ a: 1, b: 2 }[Extract<K, _Keys>]}`
: never
// Note: (As of ts4.4.4 ) Direct `keyof Obj extends infer K` Unable to split union type for unknown reason (too lazy to check 😁 ).
// The result is "a1"|"a2"|"b1"|"b2"
type Split failed = keyof { a: 1, b: 2 } extends infer K ?
`${Extract<K, string>}${{ a: 1, b: 2 }[Extract<K, "a" | "b">]}`
: never
Tuple type:
Actual (non-typed) parameters sometimes need to be explicitly defined as tuple types through as const. The tuple type can get the exact length from the tuple ["length"], not number. When tuple types are used through generic parameters, it is sometimes necessary to add a [] to be written as a tuple extends [] any [] to avoid being resolved to ordinary indefinite array types.Recursive types: Recursion of array types can be achieved with... infer More.
type Converter <T> = T extends string ? "str" : null
// Going in is a [string,number,string] When you come out, it will be ["str",null,"str"]
type Recursion <
Input source extends any[],
Internal type cache extends any[] = []
> = Input source extends [any, ...infer Residual element ] ?
Recursion < Residual element , [... Internal type cache , Converter < Input source [0]>]>
: Input source
Fragmentary
& It can be used instead of extends for type, and interface has no difference except that it can merge types with the same name. ts has a wealth of built-in types, pick a few examples: ReturnType < Function type > Gets the type of return value of the function type. Uncapitalize < String > Lock the first letter of the input string type to lowercase (others include first uppercase, all lowercase, and all uppercase).Beginners suggest going to official website to turn over documents.
After entering the ts pit, you can pay attention to the new features (gameplay) brought by the next version update.