A summary of some of the places where I spent time on TypeScript

A summary of some of the places where I spent time on TypeScript

Record some of the places where you spent time on ts.

(First of all, let me complain: stackoverflow really has everything, but Baidu is really useless)

pit

Compatibility misunderstanding of as assertion, such as "a" as "b" will not report an error.

Inconsistent behavior between interface and type (when I first encountered it, I thought I wrote the wrong type and was confused):

type Type = {
  key: "value"
}
interface Interface {
  key: "value"
}

type seems to be no different, both are true = Type extends Interface ? Type extends Interface ? true : false : false

type pit point = {
  [key: string]: pit point} | string

type test<T> = T extends pitfall? true : false
type This is true = Test <Type>
type This is false = Test <Interface>

There is an official explanation on GitHub that this pit was left intentionally. It is said that because the interface is extensible (the same name is automatically merged), it is inconvenient to detect.

When using generics to implement function overloading, in the implementation of the function, it is often necessary to use as forced assertions because generics do not have specific constraints.

//That's about it. I'm too lazy to actually test the following code 🙃

//fns is a function index table, TFns is the const type of the index table. Function overloading failed <T extends keyof TFns>(fn:T, params: Parameters<fns[T]>){
    fns[fn](...params) //In the implementation, the union type will not be narrowed, so an error will be reported //The error should be something like "cannot pass the parameters of method 1 to method 2"}
//But when used externally, it doesn't matter if the semantics of the type are met

The spread operator is not intuitive: [...string[], number] is intuitive to use (requiring a number element at the end of the array), but [...string[], null, ...object[], number] is not intuitive and will not report an error. The new version of ts adds a rule prohibiting continuous deconstruction, so this type of writing is not allowed.

Actually, there is a solution here, but the type written is simply unreadable (dozens of lines, including a large number of extends acting as type if judgments), so I will not post it. The code is posted below:

// Required types: [...number[], "middle-element", ...boolean[]] 
//The above is invalid, it just indicates what the following type code is used for (to implement the type constraints 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 error = check(false, "middle-element", 2)

Advanced Operations

Object name remapping:

//{ "new-a":any; "new-b":any }
type remap = {
    [K in "a" | "b" as `new-${K}`]: any
}

Splitting of union types: The infer keyword can be used to split union types.

//"a1"|"b2"
type split successfully <_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) Directly `keyof Obj extends infer K` cannot split the union type, the reason is unknown (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 types:

  • The actual (non-type) parameters sometimes need to be explicitly declared as tuple types using as const.
  • Tuple types can get the exact length instead of the number through tuple["length"].
  • When a tuple type is used through a generic parameter, it is sometimes necessary to add []| and write it as a tuple extends []|any[] to avoid being parsed as a normal indefinite-length array type.

Recursive types: Use ...infer More to implement recursion on array types.

type Converter<T> = T extends string ? "str" ​​: null
//It goes in as [string,number,string], and comes out as ["str",null,"str"]
type recursion<
        Input source extends any[],
        The internal type cache extends any[] = []
    > = input source extends [any, ...infer remaining elements] ?
        Recursion <remaining elements, [...internal type cache, converter <input source [0]>]>
        : Input Source

Odds and Ends

  • & can be used instead of extends for type. Interface has no other difference except that it can merge types with the same name.
  • ts has a rich set of built-in types, here are a few examples:
    • ReturnType<function type>, gets the type of the return value of the function type.
    • Uncapitalize <string>, lock the first letter of the input string type to lowercase (other options include first letter capitalization, all lowercase, and all uppercase).

It is recommended for beginners to go to the official website to read the documents.

After getting into ts, you can pay attention to the new features (gameplay) brought by version updates.

Summarize

This is the end of this article summarizing the places where I spent time on TypeScript. For more relevant content about where I spent time on TypeScript, please search for previous articles on 123WORDPRESS.COM or continue to browse the related articles below. I hope everyone will support 123WORDPRESS.COM in the future!

<<:  Detailed explanation of Tomcat core components and application architecture

>>:  HTML tags list and usage instructions

Recommend

JavaScript implements select all and unselect all operations

This article shares the specific code for JavaScr...

How to install Chrome browser on CentOS 7

This article introduces how to install Chrome bro...

Use neat HTML markup to build your pages

The Internet is an organism that is constantly ev...

Detailed explanation of Mysql transaction isolation level read commit

View MySQL transaction isolation level mysql> ...

Linux/Mac MySQL forgotten password command line method to change the password

All prerequisites require root permissions 1. End...

In-depth understanding of Linux load balancing LVS

Table of contents 1. LVS load balancing 2. Basic ...

What is this in JavaScript point by point series

Understand this Perhaps you have seen this in oth...

How to set Tomcat as an automatically started service? The quickest way

Set Tomcat to automatically start the service: I ...

How to open port 8080 on Alibaba Cloud ECS server

For security reasons, Alibaba Cloud Server ECS co...

Summary of Problems in Installing MySQL 5.7.19 under Linux

The first time I installed MySQL on my virtual ma...

Vue imitates ElementUI's form example code

Implementation requirements The form imitating El...