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

Conflict resolution when marquee and flash coexist in a page

The main symptom of the conflict is that the FLASH...

Let's talk about the performance of MySQL's COUNT(*)

Preface Basically, programmers in the workplace u...

HTML table tag tutorial (35): cross-column attribute COLSPAN

In a complex table structure, some cells span mul...

MySQL table auto-increment id overflow fault review solution

Problem: The overflow of the auto-increment ID in...

Common properties of frameset (dividing frames and windows)

A frame is a web page screen divided into several ...

How to change password in MySQL 5.7.18

How to change the password in MySQL 5.7.18: 1. Fi...

How to install and configure SSH service in Ubuntu 18.04

Install ssh tool 1. Open the terminal and type th...

Detailed explanation of MySQL user rights management

Table of contents Preface: 1. Introduction to Use...

An example of implementing a simple infinite loop scrolling animation in Vue

This article mainly introduces an example of Vue ...

What are the drawbacks of deploying the database in a Docker container?

Preface Docker has been very popular in the past ...

Div adaptive height automatically fills the remaining height

Scenario 1: Html: <div class="outer"...

Seven different color schemes for website design experience

The color matching in website construction is ver...

Introduction to Linux environment variables and process address space

Table of contents Linux environment variables and...