亚洲成A人片在线观看网站_成年网站免费视频A在线双飞_日日日日做夜夜夜夜无码_久久夜色撩人精品国产小说

TypeScript 備忘清單

包含最重要基礎、泛型、方法、class 等 TypeScript 強類型編程語言語法的快速參考備忘單。初學者的完整快速參考

入門 Interface

介紹

TypeScript 是具有類型語法的 JavaScript。Interface 是為了匹配它們的運行時行為而構建的。

內置類型基元

any, void,
boolean, string, number,
undefined, null,
unknown, never,
bigint, symbol

常見的內置 JS 對象

Date, Error,
Array, Map, Set,
Regexp, Promise

內置

類型字面量

Object:

{ field: string }

Function:

(arg: number) => string

Arrays:

string[] or Array<string>

Tuple:

[string, number]

避免

Object, String, Number, Boolean

通用語法

/** 可選擇從現有接口或類型(Response, HTTPAble)中獲取屬性 */
interface JSONResponse extends Response, HTTPAble {
  version: number;
  // ??  附加在編輯器中顯示的 JSDoc 注釋
  /** In bytes */
  payloadSize: number;
  // ??  此屬性可能不在對象上
  outOfStock?: boolean;
  // ??  這是描述作為函數的屬性的兩種方法
  update: (retryTimes: number) => void;
  update(retryTimes: number): void;
  // ??  你可以通過 () 調用這個對象 -(JS中的函數是可以調用的對象)
  (): JSONResponse
  // ??  您可以在此 Interface 描述的對象上使用 new
  new(s: string): JSONResponse;
  // ??  任何未描述的屬性都假定存在,并且所有屬性必須是數字
  [key: string]: number;
  // ??  告訴 TypeScript 一個屬性不能被改變
  readonly body: string;
}

泛型

聲明一個可以在你的 Interface 中改變的類型

interface APICall<Response> {
  data: Response
}

用法

const api: APICall<ArtworkCall> = ...

api.data  // Artwork

您可以通過 extends 關鍵字限制泛型參數接受的類型。

interface APICall<Response extends { status: number }> {
  data: Response
}

const api: APICall<ArtworkCall> = ...

api.data.status

重載

interface Expect {
  (matcher: boolean): string
  (matcher: string): boolean;
}

一個可調用 Interface 可以對不同的參數集有多個定義。

類一致性

interface Syncable {
  sync(): void
}
class Account implements Syncable { ... }

您可以通過實現確保類 class 符合 Interface。

Get & Set

對象可以有自定義的 gettersetter

interface Ruler {
  get size(): number
  set size(value: number | string);
}

用法

const r: Ruler = ...
r.size = 12
r.size = "36"

通過合并擴展

interface APICall {
  data: Response
}

interface APICall {
  error?: Error
}

Interface 被合并,多個聲明將向類型定義添加新字段。

Type

Type vs Interface

  • Interface 只能描述對象形狀
  • Interface 可以通過多次聲明來擴展
  • 在性能關鍵 Type 中,Interface 比較檢查可以更快。

把類型想象成變量

就像您如何在不同范圍內創建具有相同名稱的變量一樣,type 具有相似的語義。

使用實用程序類型構建

TypeScript 包含許多全局類型,它們將幫助您在類型系統中完成常見任務。檢查他們的網站。

原始類型

type SanitizedInput = string;
type MissingNo = 404;

主要用于文檔

對象字面類型

type Location = {
  x: number;
  y: number;
};

聯合類型

type Size = "small" | "medium" | "large"

描述許多選項中的一個類型,例如已知字符串的列表。

交叉口類型

type Location = { x: number }
              & { y: number }
// { x: number, y: number }

一種合并/擴展類型的方法

從值類型

const data = { ... }
type Data = typeof data

通過 typeof 運算符重用來自現有 JavaScript 運行時值的類型。

從函數返回類型

const createFixtures = () => { ... }
type Fixtures = ReturnType<typeof createFixtures>
function test(fixture: Fixtures) {}

將函數的返回值重新用作類型。

從模塊類型

const data: import("./data").data

這些功能非常適合構建庫、描述現有的 JavaScript 代碼,您可能會發現在大多數 TypeScript 應用程序中很少使用它們。

對象字面量語法

type JSONResponse = {
  version: number;                        // 字段
  /** In bytes */                         // 附加文檔
  payloadSize: number;
  outOfStock?: boolean;                   // 可選的
  update: (retryTimes: number) => void;   // 箭頭函數字段
  update(retryTimes: number): void;       // 函數
  (): JSONResponse                        // 類型是可調用的
  [key: string]: number;                  // 接受任何索引
  new (s: string): JSONResponse;          // new 對象
  readonly body: string;                  // 只讀屬性
}

用于節省空間的 Terser,請參閱 Interface 備忘清單了解更多信息,除了“static”匹配之外的所有內容。

映射類型

type Artist = {
  name: string, bio: string
}

type Subscriber<Type> = {
  [Property in keyof Type]: 
      (newValue: Type[Property]) => void
}
type ArtistSub = Subscriber<Artist>
// { name: (nv: string) => 
//    void, bio: (nv: string) => void }

類似于類型系統的映射語句,允許輸入類型更改新類型的結構。

模板聯合類型

type SupportedLangs =  "en" | "pt" | "zh";
type FooterLocaleIDs = "header" | "footer";
type AllLocaleIDs = `${SupportedLangs}_${FooterLocaleIDs}_id`;

// "en_header_id" | "en_footer_id"
//         | "pt_header_id" | "pt_footer_id"
//         | "zh_header_id" | "zh_footer_id"

條件類型

type HasFourLegs<Animal> = Animal extends { legs: 4 } ? Animal : never
type Animals = Bird | Dog | Ant | Wolf;
type FourLegs = HasFourLegs<Animals>
// Dog | Wolf

在類型系統中充當“if 語句”。 通過泛型創建,然后通常用于減少類型聯合中的選項數量。

控制流動分析

If 聲明

typeof(用于原語)

const input = getUserInput()
input // string | number

if (typeof input === 'string') {
 input // string
}

對象中的“property”(對于對象)

const input = getUserInput()
input  // string | { error: ... }

if ('error' in input) {
  input // { error: ... }
}

instanceof(用于類)

const input = getUserInput()
  input // number | number[]

if (input instanceof Array) {
  input // number[]
}

類型保護功能(適用于任何東西)

const input = getUserInput()
   input // number | number[]

if (Array.isArray(input)) {
  input // number[]
}

任務

const data1 = {
  name: "Zagreus"
}
// typeof data1 = {
//   name: string
// }

?? 使用 as const 縮小類型 ??

const data2 = {
  name: "Zagreus"
} as const
// typeof data1 = {
//   name: 'Zagreus'
// }

跟蹤相關變量

const response = getResponse()
const isSuccessResponse = 
    res instanceof SuccessResponse

if (isSuccessResponse) {
  res.data // SuccessResponse
}

重新分配更新類型

let data: string | number = ...
data // string | number
data = "Hello"
data // string

關鍵點

CFA 幾乎總是采用聯合,并根據代碼中的邏輯減少聯合內的類型數量。

大多數時候 CFA 在自然 JavaScript 布爾邏輯中工作,但是有一些方法可以定義您自己的函數,這些函數會影響 TypeScript 如何縮小類型。

表達式

const input = getUserInput()
input // string | number
const inputLength =
  (typeof input === "string" && input.length)
  || input
   // input: string

在進行布爾運算時,縮窄也發生在與代碼相同的行上

可識別聯合

type Responses =
  | { status: 200, data: any }
  | { status: 301, to: string }
  | { status: 400, error: Error }

用法

const response = getResponse()
response // Responses
switch(response.status) {
  case 200: return response.data
  case 301: return redirect(response.to)
  case 400: return response.error
}

斷言函數

描述影響當前范圍的 CFA 更改的函數,因為它拋出而不是返回 false。

function assertResponse(obj: any): asserts obj is SuccessResponse {
  if (!(obj instanceof SuccessResponse)) {
    throw new Error('Not a success!')
  }
}

用法

const res = getResponse():
res // SuccessResponse | ErrorResponse

// 斷言函數改變當前作用域或拋出
assertResponse(res)

res // SuccessResponse

in 操作符

interface A {
  x: number;
}
interface B {
  y: string;
}

function doStuff(q: A | B) {
  if ('x' in q) {
    // q: A
  } else {
    // q: B
  }
}

操作符可以安全的檢查一個對象上是否存在一個屬性,它通常也被作為類型保護使用

Class

創建類實例

class ABC { ... }
const abc = new ABC()

新 ABC 的參數來自構造函數。

private x 與 #private

前綴 private 是一個僅類型的添加,在運行時沒有任何影響。 在以下情況下,類之外的代碼可以進入項目:

class Bag {
  private item: any
}

Vs #private 是運行時私有的,并且在 JavaScript 引擎內部強制執行,它只能在類內部訪問:

class Bag { #item: any }

Class 上的 “this”

函數內部‘this’的值取決于函數的調用方式。 不能保證始終是您可能在其他語言中使用的類實例。

您可以使用“此參數”、使用綁定功能或箭頭功能來解決問題。

類型和值

一個類既可以用作類型也可以用作值。

const a:Bag = new Bag()

所以,小心不要這樣做:

class C implements Bag {}

通用語法

// 確保類符合一組接口或類型  ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈?┈┈╮
// 子類這個類 ┈┈┈┈┈┈┈┈↘                 ┈┈┈┈┈┈┈┈┈┈┈┈┈┴┈┈┈┈┈┈┈
class User extends Account implements Updatable, Serializable {
  id: string;                     // 一個字段
  displayName?: boolean;          // 可選字段
  name!: string;                  // '相信我,它在哪里'字段
  #attributes: Map<any, any>;     // 私人字段
  roles = ["user"];               // 具有默認值的字段
  readonly createdAt = new Date() // 具有默認值的只讀字段
  // ?? 代碼調用“new”
  constructor(id: string, email: string) {
    super(id);
    // ?? 在 `strict: true` 中,會根據字段檢查此代碼以確保其設置正確
    this.email = email;
    // ....
  };
  // ?? 描述類方法(和箭頭函數字段)的方式
  setName(name: string) { this.name = name }
  verifyName = (name: string) => { /* ... */ }

  // ?? 具有 2 個重載定義的函數
  sync(): Promise<{ ... }>
  sync(cb: ((result: string) => void)): void
  sync(cb?: ((result: string) => void)): void | Promise<{ ... }> {}
  // ?? Getters 和 setters
  get accountID() { }
  set accountID(value: string) { }
  // ?? 私有訪問只是對這個類,受保護的允許子類。 僅用于類型檢查,public 是默認值。
  private makeRequest() { ... }
  protected handleRequest() { ... }
  // ?? 靜態字段/方法
  static #userCount = 0;
  static registerUser(user: User) { ... }
  // ?? 用于設置靜態變量的靜態塊。 ‘this’指的是靜態類
  static { this.#userCount = -1 }
}

泛型

聲明一個可以在你的類方法中改變的類型。

class Box<Type> {
  contents: Type
  constructor(value: Type) {
    this.contents = value;
  }
}
const stringBox = new Box("a package")

這些功能是 TypeScript 特定的語言擴展,可能永遠無法使用當前語法進入 JavaScript。

參數屬性

class Location {
  constructor(public x: number, public y: number) {}
}
const loc = new Location(20, 40);

loc.x // 20
loc.y // 40

TypeScript 特定于類的擴展,可自動將實例字段設置為輸入參數。

抽象類

abstract class Animal {
  abstract getName(): string;
  printName() {
    console.log("Hello, " + this.getName());
  }
}
class Dog extends Animal { getName(): { ... } }

一個類可以被聲明為不可實現,但可以在類型系統中被子類化。 class 成員也可以。

裝飾器和屬性

import { Syncable, triggersSync, preferCache, required } from "mylib"

@Syncable
class User {
  @triggersSync()
  save() { ... }
  @preferCache(false)
  get displayName() { ... }
  update(@required info: Partial<User>) { ... }
}

您可以在類、類方法、訪問器、屬性和方法參數上使用裝飾器。

索引簽名

class MyClass {
  // 最好將索引數據存儲在另一個地方
  // 而不是類實例本身。
  [s: string]:
    boolean | ((s: string) => boolean);

  check(s: string) {
    return this[s] as boolean;
  }
}

類可以聲明索引簽名,與其他對象類型的索引簽名相同。

實用程序類型

Awaited<Type>

type A = Awaited<Promise<string>>;
// type A = string

type B = Awaited<Promise<Promise<number>>>;
// type B = number

type C = Awaited<boolean|Promise<number>>;
// type C = number | boolean

這種類型旨在模擬異步函數中的 await 或 Promises 上的 .then() 方法等操作 - 特別是它們遞歸解包 Promises 的方式。

Required<Type>

interface Props {
  a?: number;
  b?: string;
}

const obj: Props = { a: 5 }; 
const obj2: Required<Props> = { a: 5 };
// ? 類型“{ a: number;”中缺少屬性“b” }' 
// 但在 'Required<Props>' 類型中是必需的。

使 Type 中的所有屬性成為必需

Readonly<Type>

interface Todo {
  title: string;
}
const todo: Readonly<Todo> = {
  title: "Delete inactive users",
};
todo.title = "Hello";
// ? 無法分配給“title”,因為它是只讀屬性。

function freeze<Type>(obj: Type)
            : Readonly<Type>;

將 Type 中的所有屬性設為只讀

Partial<Type>

interface Todo {
  title: string;
  description: string;
}
function updateTodo(
  todo: Todo,
  fieldsToUpdate: Partial<Todo>
) {
  return { ...todo, ...fieldsToUpdate };
}
const todo1 = {
  title: "organize desk",
  description: "clear clutter",
};
const todo2 = updateTodo(todo1, {
  description: "throw out trash",
});

Type 中的所有屬性設為可選

Record<Keys, Type>

interface CatInfo {
  age: number;
  breed: string;
}

type CatName = "miffy" | "boris";
const cats: Record<CatName, CatInfo> = {
  miffy: {age:10, breed: "Persian" },
  boris: {age:5, breed: "Maine Coon" },
};

cats.boris; 
// ?? const cats: Record<CatName, CatInfo>

構造一個具有一組 Keys 類型的屬性 Type 的類型

Pick<Type, Keys>

interface Todo {
  name: string;
  description: string;
  completed: boolean;
}
type TodoPreview = Pick<
  Todo, "name" | "load"
>;
const todo: TodoPreview = {
  name: "Clean room",
  load: false,
};

todo;
 // ?? const todo: TodoPreview

從 Type 中選擇一組其鍵在并集 Keys 中的屬性

Exclude<UnionType, ExcludedMembers>

type T0 = Exclude<"a" | "b" | "c", "a">;
// ?? type T0 = "b" | "c"

type T1 = Exclude<"a"|"b"|"c", "a" | "b">;
// ?? type T1 = "c"

type T2 = Exclude<string | number |
    (() => void), Function>;
// ?? type T2 = string | number

UnionType排除那些可分配給 ExcludedMembers 的類型

Extract<Type, Union>

type T0 = Extract<
  "a" | "b" | "c", "a" | "f"
>;
// type T0 = "a"
type T1 = Extract<
  string | number | (() => void),
  Function
>;
// type T1 = () => void

通過從 Type 中提取所有可分配給 Union 的聯合成員來構造一個類型。

NonNullable<Type>

type T0 = NonNullable<
  string | number | undefined
>;
// type T0 = string | number

type T1 = NonNullable<
  string[] | null | undefined
>;
// type T1 = string[]

通過從 Type 中排除 null 和 undefined 來構造一個類型。

Omit<Type, Keys>

interface Todo {
  name: string;
  completed: boolean;
  createdAt: number;
}
 
type TodoPreview = Omit<Todo, "name">;

const todo: TodoPreview = {
  completed: false,
  createdAt: 1615544252770,
};
 
todo;
 // ?? const todo: TodoPreview

構造一個具有 Type 屬性的類型,但類型 Keys 中的屬性除外

Parameters<Type>

declare function f1(
  arg: { a: number; b: string }
): void;

type T0 = Parameters<() => string>;
// type T0 = []
type T1 = Parameters<(s: string) => void>;
// type T1 = [s: string]
type T2 = Parameters<<T>(arg: T) => T>;
// type T2 = [arg: unknown]
type T3 = Parameters<typeof f1>;
// type T3 = [arg: {
//     a: number;
//     b: string;
// }]
type T4 = Parameters<any>;
// type T4 = unknown[]
type T5 = Parameters<never>;
// type T5 = never

從函數類型 Type 的參數中使用的類型構造元組類型。

ConstructorParameters<Type>

type T0 = ConstructorParameters<
  ErrorConstructor
>;
// type T0 = [message?: string]
type T1 = ConstructorParameters<
  FunctionConstructor
>;
// type T1 = string[]
type T2 = ConstructorParameters<
  RegExpConstructor
>;
// type T2 = [
//    pattern: string | RegExp,
//    flags?: string
// ]
type T3 = ConstructorParameters<any>;
// type T3 = unknown[]

從構造函數類型的類型構造元組或數組類型。它產生一個包含所有參數類型的元組類型(如果 Type 不是函數,則類型 never )。

內在字符串操作類型

Uppercase<StringType>

type Greeting = "Hello, world"
type ShoutyGreeting = Uppercase<Greeting>
// type ShoutyGreeting = "HELLO, WORLD"

type ASCIICacheKey<Str extends string> = `ID-${Uppercase<Str>}`
type MainID = ASCIICacheKey<"my_app">
// type MainID = "ID-MY_APP"

將字符串中的每個字符轉換為大寫版本。

Lowercase<StringType>

type Greeting = "Hello, world"
type QuietGreeting = Lowercase<Greeting>
// type QuietGreeting = "hello, world"

type ASCIICacheKey<Str extends string> = `id-${Lowercase<Str>}`
type MainID = ASCIICacheKey<"MY_APP">
// type MainID = "id-my_app"

將字符串中的每個字符轉換為等效的小寫字母

Capitalize<StringType>

type LowercaseGreeting = "hello, world";
type Greeting = Capitalize<LowercaseGreeting>;
// type Greeting = "Hello, world"

將字符串中的第一個字符轉換為等效的大寫字母

Uncapitalize<StringType>

type UppercaseGreeting = "HELLO WORLD";
type UncomfortableGreeting = Uncapitalize<UppercaseGreeting>;
// type UncomfortableGreeting = "hELLO WORLD"

將字符串中的第一個字符轉換為等效的小寫字母

ReturnType<Type>

declare function f1(): {
  a: number; b: string
};

type T0 = ReturnType<() => string>;
// type T0 = string

type T1 = ReturnType<(s: string) => void>;
// type T1 = void

type T2 = ReturnType<<T>() => T>;
// type T2 = unknown

type T3 = ReturnType<<
  T extends U, U extends number[]
>() => T>;
// type T3 = number[]

type T4 = ReturnType<typeof f1>;
// type T4 = {
//     a: number;
//     b: string;
// }

type T5 = ReturnType<any>;
// type T5 = any

type T6 = ReturnType<never>;
// type T6 = never

構造一個由函數 Type 的返回類型組成的類型。

ThisType<Type>

type ObjectDescriptor<D, M> = {
  data?: D;
  // 方法中“this”的類型是 D & M
  methods?: M & ThisType<D & M>;
};
 
function makeObject<D, M>(
  desc: ObjectDescriptor<D, M>
): D & M {
  let data: object = desc.data || {};
  let methods: object = desc.methods || {};
  return { ...data, ...methods } as D & M;
}
 
let obj = makeObject({
  data: { x: 0, y: 0 },
  methods: {
    moveBy(dx: number, dy: number) {
      this.x += dx; // Strongly typed this
      this.y += dy; // Strongly typed this
    },
  },
});
 
obj.x = 10;
obj.y = 20;
obj.moveBy(5, 5);

此實用程序不返回轉換后的類型。 相反,它用作上下文 this 類型的標記。 請注意,必須啟用 標志才能使用此實用程序。

InstanceType<Type>

class C {
  x = 0;
  y = 0;
}
type T0 = InstanceType<typeof C>;
// type T0 = C
type T1 = InstanceType<any>;
// type T1 = any
type T2 = InstanceType<never>;
// type T2 = never

構造一個由 Type 中構造函數的實例類型組成的類型。

ThisParameterType<Type>

function toHex(this: Number) {
  return this.toString(16);
}
 
function numberToString(
  n: ThisParameterType<typeof toHex>
) {
  return toHex.apply(n);
}

提取函數類型的 this 參數的類型,如果函數類型沒有 this 參數,則為未知。

OmitThisParameter<Type>

function toHex(this: Number) {
  return this.toString(16);
}
const fiveToHex
  : OmitThisParameter<typeof toHex>
  = toHex.bind(5);

console.log(fiveToHex());

從 Type 中移除 this 參數。 如果 Type 沒有顯式聲明此參數,則結果只是 Type。 否則,從 Type 創建一個不帶此參數的新函數類型。 泛型被刪除,只有最后一個重載簽名被傳播到新的函數類型中。

JSX

JSX 介紹

JSX 規范是對 ECMAScript 的類似 XML 的語法擴展。

  • 使用 .tsx 擴展名命名您的文件
  • 啟用 jsx 選項
  • 不允許在 .tsx 文件中使用尖括號類型斷言。

as 運算符

const foo = <foo>bar;
// ? 不允許在 .tsx ?? 文件中使用尖括號類型斷言。

const foo = bar as foo;

as 運算符在 .ts.tsx 文件中都可用,并且在行為上與尖括號類型斷言樣式相同。

基于值的元素

import MyComponent from "./myComponent";

<MyComponent />; // ok
<SomeOtherComponent />; // ? error

基于值的元素只是由范圍內的標識符查找。

內在的元素

declare namespace JSX {
  interface IntrinsicElements {
    foo: any;
  }
}
<foo />; // ok
<bar />; // error

<bar /> 沒有在 JSX.IntrinsicElements 上指定。

declare namespace JSX {
  interface IntrinsicElements {
    [elemName: string]: any;
  }
}

函數組件

interface FooProp {
  name: string;
  X: number;
  Y: number;
}
declare function AnotherComponent(prop: { name: string });
function ComponentFoo(prop: FooProp) {
  return <AnotherComponent name={prop.name} />;
}

const Button = (prop: { value: string }, context: { color: string }) => (
  <button />
);

該組件被定義為一個 JavaScript 函數,其第一個參數是一個 props 對象。 TS 強制它的返回類型必須可分配給 JSX.Element。

函數組件重載

interface CeProps {
  children: JSX.Element[] | JSX.Element;
}
 
interface HomeProps extends CeProps {
  home: JSX.Element;
}
 
interface SideProps extends CeProps {
  side: JSX.Element | string;
}
 
function Dog(prop:HomeProps): JSX.Element;
function Dog(prop:SideProps): JSX.Element;
function Dog(prop:CeProps): JSX.Element {
  // ...
}

函數子組件

interface MenuProps extends React.LiHTMLAttributes<HTMLUListElement> { ... }
const InternalMenu = (props: MenuProps, ref?: React.ForwardedRef<HTMLUListElement>) => (
  <ul {...props} ref={ref} />
);
type MenuComponent = React.FC<React.PropsWithRef<MenuProps>> & {
  Item: typeof MenuItem;    // MenuItem 函數組件
  SubMenu: typeof SubMenu;  // SubMenu 函數組件
};
const Menu: MenuComponent = React.forwardRef<HTMLUListElement>(
  InternalMenu
) as unknown as MenuComponent;

Menu.Item = MenuItem;
Menu.SubMenu = SubMenu;

<Menu.Item />     // ? ok
<Menu.SubMenu />  // ? ok

有效組件

declare namespace JSX {
  interface ElementClass {
    render: any;
  }
}
class MyComponent {
  render() {}
}
function MyFactoryFunction() {
  return { render: () => {} };
}
<MyComponent />;       // ? 有效類組件
<MyFactoryFunction />; // ? 有效函數組件

元素實例類型必須可以分配給 JSX.ElementClass,否則將導致錯誤。

class NotAValidComponent {}
function NotAValidFactoryFunction() {
  return {};
}
<NotAValidComponent />; // ? error
<NotAValidFactoryFunction />; // ? error

默認情況下,JSX.ElementClass 是 {},但可以對其進行擴展,以將 JSX 的使用限制為僅限于符合適當接口的類型。

類組件

type Props = {
  header: React.ReactNode;
  body: React.ReactNode;
};

class MyComponent extends React.Component<Props, {}> {
  render() {
    return (
      <div>
        {this.props.header}
        {this.props.body}
      </div>
    );
  }
}

<MyComponent header={<h1>Header</h1>} body={<i>body</i>} />

泛型組件

// 一個泛型組件
type SelectProps<T> = { items: T[] };
class Select<T> extends React.Component<SelectProps<T>, any> {}

// 使用
const Form = () => <Select<string> items={['a', 'b']} />;

函數組件 ref

import { FC, ForwardedRef, forwardRef, PropsWithRef } from "react";

function InternalProgress(props: ProgressProps, ref?: ForwardedRef<HTMLDivElement>) {
  return (
    <div {...props} ref={ref}>
      {props.children}
    </div>
  )
}

export interface ProgressProps extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> {}
export const Progress: FC<PropsWithRef<ProgressProps>> = forwardRef<HTMLDivElement>(InternalProgress)

各種各樣的技巧

類型推導(infer)

type Capitalize<T extends string> = T extends `${infer U}${infer V}`
  ? `${Uppercase<U>}${V}`
  : T
type capitalized = Capitalize<"hello world"> // Hello World

也可以在 infer 中使用條件約束(extends

type SomeBigInt = "100" extends `${infer U extends bigint}` ? U : never;
// 100n

keyof 取 interface 的鍵

interface Point {
    x: number;
    y: number;
}
 
// type keys = "x" | "y"
type keys = keyof Point;

索引簽名

interface NumberOrString {
  [index: string]: string | number;
  length: number;
  name: string;
}

從數組中提取類型

type Point = { x: number; y: number; }
type Data = Point[];
// Data 是個數組,提取里面的元素類型
type PointDetail = Data[number];
// type PointDetail = { x: number; y: number; }

只讀元組類型

const point = [3, 4] as const
// type 'readonly [3, 4]'

satisfies

satisfies 允許將驗證表達式的類型與某種類型匹配,而無需更改該表達式的結果類型。

type Colors = 'red' | 'green' | 'blue';
type RGB = [
  red: number,
  green: number,
  blue: number
];
type Palette = Record<Colors, string | RGB>

const palette: Palette = {
  red: [255, 0, 0],
  green: '#00ff00',
  blue: [0, 0, 255],
};

// 通常的方式會推導出 redComponent 為
// => string | number | undefined
const redComponent = palette.red.at(0);

使用 satisfies

const palette = {
  red: [255, 0, 0],
  green: '#00ff00',
  blue: [0, 0, 255],
} satisfies Record<Colors, string | RGB>

// undefined | number
const redComponent = palette.red.at(0)

范型實例化表達式

不使用的情況下:

const errorMap: Map<string, Error> = new Map()
// 或者使用 type 定義別名
type ErrorMapType = Map<string, Error>

使用泛型實例化表達式:

const ErrorMap = Map<string, Error>
const errorMap = new ErrorMap()

泛型實例化函數

function makeBox<T>(value: T) {
    return { value };
}

不使用:

function makeHammerBox(hammer: Hammer) {
  return makeBox(hammer);
}
// or...
const makeWrenchBox: (wrench: Wrench) => Box<Wrench> = makeBox;

使用:

const makeStringBox = makeBox<string>;
makeStringBox(42);

識別全局修改模塊

declare global {
  interface String {
    fancyFormat(opts: FancyOption): string;
  }
}
export interface FancyOption {
  fancinessLevel: number;
}

.d.ts 模版

Module: Plugin

例如,當您想使用擴展另一個庫的 JavaScript 代碼時

import { greeter } from "super-greeter";
// 普通歡迎 API
greeter(2);
greeter("Hello world");
// 現在我們在運行時用一個新函數擴展對象
import "hyper-super-greeter";
greeter.hyperGreet();

"super-greeter" 的定義:

/* 此示例說明如何為您的函數設置多個重載 */
export interface GreeterFunction {
  (name: string): void
  (time: number): void
}
/* 此示例顯示如何導出接口指定的函數 */
export const greeter: GreeterFunction;

我們可以像下面這樣擴展現有模塊:

/* 導入這個模塊添加到的模塊 */
import { greeter } from "super-greeter";
/* 聲明與上面導入的模塊相同的模塊,然后我們擴展 greeter 函數的現有聲明 */
export module "super-greeter" {
  export interface GreeterFunction {
    /** Greets even better! */
    hyperGreet(): void;
  }
}

全局庫模板 Global .d.ts

全局庫可能如下所示:

function createGreeting(s) {
  return "Hello, " + s;
}

或者像這樣:

window.createGreeting = function (s) {
  return "Hello, " + s;
};

類型聲明示例

/* 可以作為 myLib(3) 此處包含這些調用簽名 */
declare function myLib(a: string): string;
declare function myLib(a: number): number;
/* 如果你希望這個庫的名稱是一個有效的類型名稱,你可以在這里這樣做例如,這允許我們寫 'var x: myLib'; 確保這確實有意義! 如果沒有,只需刪除此聲明并在下面的命名空間內添加類型 */
interface myLib {
  name: string;
  length: number;
  extras?: string[];
}
/* 如果您的庫在全局變量上公開了屬性,請將它們放在此處。 您還應該在此處放置類型(接口和類型別名) */
declare namespace myLib {
  // 我們可以寫 'myLib.timeout = 50;'
  let timeout: number;
  // 我們可以訪問 'myLib.version',但不能更改它
  const version: string;
  // 我們可以通過 'let c = new myLib.Cat(42)' 創建一些類或參考例如 '函數 f(c: myLib.Cat) { ... }
  class Cat {
    constructor(n: number);
    // 我們可以從 'Cat' 實例中讀取 'c.age' 
    readonly age: number;
    // 我們可以從 'Cat' 實例調用 'c.purr()' 
    purr(): void;
  }
  // 我們可以將變量聲明為
  //    'var s: myLib.CatSettings = { weight: 5, name: "Maru" };'
  interface CatSettings {
    weight: number;
    name: string;
    tailLength?: number;
  }
  // 我們可以寫 'const v: myLib.VetID = 42;'
  //   或 'const v: myLib.VetID = "bob";'
  type VetID = string | number;
  // 我們可以調用 'myLib.checkCat(c)' 或 'myLib.checkCat(c, v);'
  function checkCat(c: Cat, s?: VetID);
}

Module: Function

import greeter from "super-greeter";
greeter(2);
greeter("Hello world");

要處理通過 UMD 和模塊導入:

/* 如果此模塊是一個 UMD 模塊,在模塊加載器環境之外加載時公開全局變量“myFuncLib”,請在此處聲明該全局變量。 否則,刪除此聲明 */
export as namespace myFuncLib;
/* 此聲明指定該函數是從文件中導出的對象 */
export = Greeter;
/* 此示例說明如何為您的函數設置多個重載 */
declare function Greeter(name: string): Greeter.NamedReturnType;
declare function Greeter(length: number): Greeter.LengthReturnType;

如果你也想從你的模塊中公開類型,你可以把它們放在這個塊中。 通常你會想要描述函數返回類型的形狀; 如本例所示,應在此處聲明該類型,請注意,如果您決定包含此命名空間,則模塊可能會被錯誤地導入為命名空間對象,除非 --esModuleInterop 已打開: import * as x from '[~THE MODULE~]'; 錯誤的!不要這樣做!

declare namespace Greeter {
  export interface LengthReturnType {
    width: number;
    height: number;
  }
  export interface NamedReturnType {
    firstName: string;
    lastName: string;
  }
  /**
   * 如果模塊也有屬性,在這里聲明它們。 例如,這個聲明說這個代碼是合法的:
   *  import f = require('super-greeter');
   *  console.log(f.defaultName);
   */
  export const defaultName: string;
  export let defaultLength: number;
}

Module: Class

例如,當您想要使用如下所示的 JavaScript 代碼時:

const Greeter = require("super-greeter");
const greeter = new Greeter();
greeter.greet();

要處理通過 UMD 和模塊導入:

export as namespace "super-greeter";
/* 此聲明指定類構造函數是從文件中導出的對象 */
export = Greeter;
/* 在此類中編寫模塊的方法和屬性 */
declare class Greeter {
  constructor(customGreeting?: string);
  greet: void;
  myMethod(opts: MyClass.MyClassMethodOptions): number;
}

如果你也想從你的模塊中公開類型,你可以把它們放在這個塊中,如果您決定包含此命名空間,則模塊可能會被錯誤地導入為命名空間對象,除非 --esModuleInterop 已打開: import * as x from '[~THE MODULE~]'; 錯誤的! 不要這樣做!

declare namespace MyClass {
  export interface MyClassMethodOptions {
    width?: number;
    height?: number;
  }
}

CLI

使用 CLI

# 基于向后查看 tsconfig.json 的 fs 運行編譯
$ tsc
# 使用編譯器默認值僅為 index.ts 發射 JS
$ tsc index.ts
# 使用默認設置為文件夾 src 中的任何 .ts 文件發出 JS
$ tsc src/*.ts
# 使用 tsconfig.production.json 中的編譯器設置發出引用的文件
$ tsc --project tsconfig.production.json
# 為 js 文件發出 d.ts 文件,顯示布爾值的編譯器選項
$ tsc index.js --declaration --emitDeclarationOnly
# 通過采用字符串參數的編譯器選項從兩個文件發出單個 .js 文件
$ tsc app.ts util.ts --target esnext --outfile index.js

編譯器選項

:---
--all boolean顯示所有編譯器選項
--generateTrace string生成事件跟蹤和類型列表
--help boolean提供有關 CLI 幫助的本地信息
--init boolean初始化 TypeScript 項目并創建 tsconfig.json 文件
--listFilesOnly boolean打印作為編譯一部分的文件名,然后停止處理
--locale string設置來自 TypeScript 的消息傳遞語言。 這不影響發射
--project string編譯項目給定其配置文件的路徑,或帶有 'tsconfig.json' 的文件夾
--showConfig boolean打印最終配置而不是構建
--version boolean打印編譯器的版本

構建選項

:---
--build boolean構建一個或多個項目及其依賴項(如果已過期)
--clean boolean刪除所有項目的輸出
--dry boolean顯示將構建的內容(或刪除,如果使用“--clean”指定)
--force boolean構建所有項目,包括那些看起來是最新的項目
--verbose boolean啟用詳細日志記錄

監聽選項

:---
--excludeDirectories list從監視進程中刪除目錄列表
--excludeFiles list從監視模式的處理中刪除文件列表
--fallbackPolling fixedinterval, priorityinterval, dynamicpriority, fixedchunksize指定當系統用完本機文件觀察器時觀察器應使用的方法
--synchronousWatchDirectory boolean在本機不支持遞歸監視的平臺上同步調用回調并更新目錄監視程序的狀態
--watch boolean觀看輸入文件
--watchDirectory usefsevents, fixedpollinginterval, dynamicprioritypolling, _fixedchunksizepolling指定在缺少遞歸文件監視功能的系統上如何監視目錄
--watchFile fixedpollinginterval, prioritypollinginterval, dynamicprioritypolling, fixedchunksizepolling, usefsevents, usefseventsonparentdirectory指定 TypeScript 監視模式的工作方式

TSConfig Ref

頂層配置

:---
files 指定要包含在程序中的文件的允許列表
extends 包含要繼承的另一個配置文件的路徑
include 指定要包含在程序中的文件名或模式數組
exclude 指定解析包含時應跳過的文件名或模式數組
references 項目引用是一種將 TypeScript 程序構造成更小部分的方法

{
  "extends": "./tsconfig",
  "compilerOptions": {
    "strictNullChecks": false
  }
}

類型檢查(compilerOptions)

:---
allowUnreachableCode 允許無法訪問的代碼
allowUnusedLabels 允許未使用的標簽
alwaysStrict 始終嚴格
exactOptionalPropertyTypes 啟用后,TypeScript 應用更嚴格的規則來處理它如何處理類型或具有 ? 字首
noFallthroughCasesInSwitch 在 switch 語句中報告失敗案例的錯誤
noImplicitAny 在某些不存在類型注釋的情況下,TypeScript 將在無法推斷類型時回退到變量的任何類型
noImplicitOverride 當處理使用繼承的類時,子類可能與在基類中重命名時重載的函數“不同步”
noImplicitReturns 沒有隱式返回
noImplicitThis 使用隱含的“any”類型在“this”表達式上引發錯誤
noPropertyAccessFromIndexSignature 此設置確保通過“點”(obj.key)語法訪問字段和“索引”(obj[“key”])以及在類型中聲明屬性的方式之間的一致性
noUncheckedIndexedAccess TypeScript 有一種方法可以通過索引簽名來描述對象上具有未知鍵但已知值的對象
noUnusedLocals 報告未使用的局部變量的錯誤
noUnusedParameters 報告函數中未使用參數的錯誤
strict 嚴格標志啟用了范圍廣泛的類型檢查行為,從而更有效地保證了程序的正確性
strictBindCallApply TypeScript 將檢查函數調用、綁定和應用的內置方法是否使用底層函數的正確參數調用
strictFunctionTypes 此標志會導致更正確地檢查函數參數
strictNullChecks 嚴格的空檢查
strictPropertyInitialization 嚴格的屬性初始化
useUnknownInCatchVariables 在 TypeScript 4.0 中,添加了支持以允許將 catch 子句中的變量類型從 any 更改為 unknown

模塊(compilerOptions)

:---
allowUmdGlobalAccess 為 true 時,將允許你在模塊文件中以全局變量的形式訪問 UMD 的導出
baseUrl 可以讓您設置解析非絕對路徑模塊名時的基準目錄
module 設置程序的模塊系統
moduleResolution 指定模塊解析策略:'node'(Node.js)或 'classic'
moduleSuffixes 提供一種在解析模塊時覆蓋要搜索的默認文件名后綴列表的方法
noResolve 默認情況下,TypeScript 將檢查導入和 <reference 指令的初始文件集,并將這些解析的文件添加到您的程序中
paths 一些將模塊導入重新映射到相對于 baseUrl 路徑的配置
resolveJsonModule 允許導入帶有“.json”擴展名的模塊,這是 node 項目中的常見做法
rootDir 默認: 所有輸入的非聲明文件中的最長公共路徑
rootDirs 通過 rootDirs,你可以告訴編譯器有許多“虛擬”的目錄作為一個根目錄
typeRoots 默認情況下,所有 可見 的 ”@types” 包都將包含在你的編譯過程中
types 默認情況下,所有 可見 的 ”@types” 包都將包含在你的編譯過程中

Emit(compilerOptions)

:---
declaration 為項目中的每個 TypeScript 或 JavaScript 文件生成 .d.ts 文件
declarationDir 提供一種配置發出聲明文件的根目錄的方法
declarationMap 為映射回原始 .ts 源文件的 .d.ts 文件生成源映射
downlevelIteration 降級是 TypeScript 的術語,用于轉譯到舊版本的 JavaScript
emitBOM 控制 TypeScript 在寫入輸出文件時是否會發出字節順序標記 (BOM)
emitDeclarationOnly 只發出 .d.ts 文件;不要發出 .js 文件
importHelpers 對于某些降級操作,TypeScript 使用一些輔助代碼來執行擴展類、展開數組或對象以及異步操作等操作
importsNotUsedAsValues 此標志控制導入的工作方式,有 3 個不同的選項: remove, preserve, error
inlineSourceMap 設置后,TypeScript 不會寫出 .js.map 文件來提供源映射,而是將源映射內容嵌入到 .js 文件中
inlineSources 設置后,TypeScript 會將 .ts 文件的原始內容作為嵌入字符串包含在源映射中(使用源映射的 sourcesContent 屬性)
mapRoot 指定調試器應該定位映射文件而不是生成位置的位置
newLine 指定發出文件時要使用的行尾順序:“CRLF”(dos)或“LF”(unix)
noEmit 不要發出編譯器輸出文件,如 JavaScript 源代碼、源映射或聲明
noEmitHelpers 您可以在全局范圍內為您使用的助手提供實現,并完全關閉助手函數的發出,而不是使用 importHelpers 導入助手
noEmitOnError 如果報告了任何錯誤,請不要發出編譯器輸出文件,如 JavaScript 源代碼、源映射或聲明
outDir 如果指定,.js(以及 .d.ts、.js.map 等)文件將被發送到此目錄中
outFile 如果指定,所有全局(非模塊)文件將連接到指定的單個輸出文件中
preserveConstEnums 不要刪除生成的代碼中的 const enum 聲明
preserveValueImports 在某些情況下,TypeScript 無法檢測到您正在使用導入
removeComments 轉換為 JavaScript 時從 TypeScript 文件中刪除所有注釋
sourceMap 啟用源映射文件的生成
sourceRoot 指定調試器應定位 TypeScript 文件的位置,而不是相對源位置
stripInternal 不要為在其 JSDoc 注釋中具有 @internal 注釋的代碼發出聲明

JavaScript 支持(compilerOptions)

:---
allowJs 允許 JavaScript 文件在你的工程中被引入,而不是僅僅允許 .ts 和 .tsx 文件
checkJs 與 allowJs 配合使用,當 checkJs 被啟用時,JavaScript 文件中會報告錯誤
maxNodeModuleJsDepth 在 node_modules 下搜索和加載 JavaScript 文件的最大依賴深度

編輯器支持(compilerOptions)

:---
disableSizeLimit 分配的內存量有一個上限。打開此標志將刪除限制
plugins 可在編輯器內運行的語言服務插件列表

互操作約束(compilerOptions)

:---
allowSyntheticDefaultImports 允許合成默認導入
esModuleInterop ES 模塊互操作
forceConsistentCasingInFileNames 在文件名中強制使用一致的大小寫
isolatedModules 隔離模塊
preserveSymlinks 保留符號鏈接

向后兼容性(compilerOptions)

:---
charset 在早期版本的 TypeScript 中,這控制了從磁盤讀取文本文件時使用的編碼
keyofStringsOnly 此標志將 keyof 類型運算符更改為返回 string 而不是 `string
noImplicitUseStrict 默認情況下,當向非 ES6 目標發出模塊文件時,TypeScript 發出"use strict";文件頂部的序言。此設置禁用序言
noStrictGenericChecks TypeScript 在比較兩個泛型函數時會統一類型參數
out 請改用 outFile
suppressExcessPropertyErrors 抑制過多的屬性錯誤
suppressImplicitAnyIndexErrors 抑制隱式任何索引錯誤

完整性(compilerOptions)

:---
skipDefaultLibCheck 請改用 skipLibCheck
skipLibCheck 跳過聲明文件的類型檢查

語言與環境(compilerOptions)

:---
emitDecoratorMetadata 發射裝飾器元數據
experimentalDecorators 實驗裝飾器
jsx 控制 JSX 在 JavaScript 文件中的輸出方式
jsxFactory 使用經典 JSX 運行時編譯 JSX 元素時更改在 .js 文件中調用的函數
jsxFragmentFactory 指定在使用 jsxFactory 編譯器選項指定 react JSX emit 時要使用的 JSX 片段工廠函數,例如 Fragment
jsxImportSource 聲明模塊說明符用于在將 jsx 用作 TypeScript 4.1 中引入的“react-jsx”或“react-jsxdev”時導入 jsx 和 jsxs 工廠函數
lib TypeScript 包括一組默認的內建 JS 接口(例如 Math)的類型定義,以及在瀏覽器環境中存在的對象的類型定義(例如 document)
moduleDetection 模塊檢測
noLib 禁用自動包含任何庫文件
reactNamespace 請改用 jsxFactory
target 現代瀏覽器支持全部 ES6 的功能,所以 ES6 是一個不錯的選擇
useDefineForClassFields 為類字段使用定義

輸出格式(compilerOptions)

:---
noErrorTruncation 不要截斷錯誤消息
preserveWatchOutput 保留監視輸出
pretty 使用顏色和上下文對錯誤和消息進行樣式化,默認情況下啟用

項目(compilerOptions)

:---
composite composite 選項會強制執行某些約束,使得構建工具(包括 在 --build 模式下的 TypeScript 本身)可以快速確定一個工程是否已經建立
disableReferencedProjectLoad 禁用引用項目加載
disableSolutionSearching 禁用解決方案搜索
disableSourceOfProjectReferenceRedirect 禁用源項目引用重定向
incremental 使 TypeScript 將上次編譯的工程圖信息保存到磁盤上的文件中
tsBuildInfoFile 這個選項可以讓您指定一個文件來存儲增量編譯信息,以作為復合工程的一部分,從而可以更快的構建更大的 TypeScript 代碼庫

編譯器診斷(compilerOptions)

:---
diagnostics 用于輸出調試信息
explainFiles 打印 TypeScript 視為項目一部分的文件的名稱以及它們是編譯一部分的原因
extendedDiagnostics 您可以使用此標志來發現 TypeScript 在編譯時將時間花在哪里
generateCpuProfile 此選項使您有機會讓 TypeScript 在編譯器運行期間發出 v8 CPU 配置文件
listEmittedFiles 將編譯過程中生成的文件的名稱打印到終端
listFiles 打印編譯部分文件的名稱
traceResolution 當您嘗試調試未包含模塊的原因時

監聽選項(watchOptions)

:---
watchFile 如何監視單個文件的策略
watchDirectory 在缺乏遞歸文件監視功能的系統下監視整個目錄樹的策略
fallbackPolling 使用文件系統事件時,此選項指定當系統用完本機文件觀察器和/或不支持本機文件觀察器時使用的輪詢策略
synchronousWatchDirectory 在本機不支持遞歸監視的平臺上同步調用回調并更新目錄監視程序的狀態
excludeDirectories 您可以使用 excludeFiles 來大幅減少在 --watch 期間監視的文件數量
excludeFiles 您可以使用 excludeFiles 從監視的文件中刪除一組特定文件

{
  "watchOptions": {
    "synchronousWatchDirectory": true
  }
}

類型采集(typeAcquisition)

:---
enable 提供用于在 JavaScript 項目中禁用類型獲取的配置
include 如果您有一個 JavaScript 項目,其中 TypeScript 需要額外的指導來理解全局依賴關系,或者已通過 disableFilenameBasedTypeAcquisition 禁用了內置推理
exclude 提供用于禁用 JavaScript 項目中特定模塊的類型獲取的配置
disableFilenameBasedTypeAcquisition TypeScript 的類型獲取可以根據項目中的文件名推斷出應該添加哪些類型

{
  "typeAcquisition": {
    "enable": false
  }
}

另見