TypeScript 3.0

專案引用 (Project References)

TypeScript 3.0 引入了專案引用的新概念。專案引用允許 TypeScript 專案依賴於其他 TypeScript 專案——具體來說,就是允許 tsconfig.json 檔案引用其他 tsconfig.json 檔案。明確這些依賴關係可以更輕鬆地將程式碼拆分為更小的專案,因為它為 TypeScript(及其周邊的工具)提供了一種理解構建順序和輸出結構的方法。

TypeScript 3.0 還為 tsc 引入了一種新模式,即 --build 標誌。它與專案引用協同工作,從而實現更快的 TypeScript 構建。

有關更多文件,請參閱 專案引用手冊頁面

剩餘引數和展開表示式中的元組

TypeScript 3.0 增加了對多項新功能的支援,以將函式引數列表作為元組型別進行互動。TypeScript 3.0 增加了對以下內容的支援:

利用這些特性,可以為許多轉換函式及其引數列表的高階函式提供強大的型別支援。

帶有元組型別的剩餘引數

當剩餘引數具有元組型別時,該元組型別會被展開為一系列離散的引數。例如,以下兩個宣告是等價的:

ts
declare function foo(...args: [number, string, boolean]): void;
ts
declare function foo(args_0: number, args_1: string, args_2: boolean): void;

帶有元組型別的展開表示式

當函式呼叫包含一個元組型別的展開表示式作為最後一個引數時,該展開表示式對應於元組元素型別的一系列離散引數。

因此,以下呼叫是等價的:

ts
const args: [number, string, boolean] = [42, "hello", true];
foo(42, "hello", true);
foo(args[0], args[1], args[2]);
foo(...args);

泛型剩餘引數

剩餘引數允許具有約束為陣列型別的泛型型別,並且型別推斷可以為此類泛型剩餘引數推斷元組型別。這使得可以實現高階捕獲和部分引數列表的展開。

示例
ts
declare function bind<T, U extends any[], V>(
f: (x: T, ...args: U) => V,
x: T
): (...args: U) => V;
declare function f3(x: number, y: string, z: boolean): void;
const f2 = bind(f3, 42); // (y: string, z: boolean) => void
const f1 = bind(f2, "hello"); // (z: boolean) => void
const f0 = bind(f1, true); // () => void
f3(42, "hello", true);
f2("hello", true);
f1(true);
f0();

在上述 f2 的宣告中,型別推斷分別為 TUV 推斷出 number[string, boolean]void 型別。

請注意,當從一系列引數推斷出元組型別並隨後將其展開為引數列表時(如 U 的情況),原始引數名稱會用於展開(但是,這些名稱沒有語義含義,在其他情況下是不可見的)。

元組型別中的可選元素

元組型別現在允許在元素型別後新增 ? 字尾,以表示該元素是可選的。

示例
ts
let t: [number, string?, boolean?];
t = [42, "hello", true];
t = [42, "hello"];
t = [42];

strictNullChecks 模式下,? 修飾符會自動將 undefined 包含在元素型別中,這類似於可選引數。

如果元組型別在其元素型別上具有後綴 ? 修飾符,並且其右側的所有元素也都具有 ? 修飾符,則允許省略該元素。

當為剩餘引數推斷元組型別時,源中的可選引數在推斷出的型別中將變為可選元組元素。

具有可選元素的元組型別的 length 屬性是代表可能長度的數字字面量型別的聯合。例如,元組型別 [number, string?, boolean?]length 屬性的型別為 1 | 2 | 3

元組型別中的剩餘元素

元組型別的最後一個元素可以是 ...X 形式的剩餘元素,其中 X 是一個數組型別。剩餘元素表示元組型別是開放式的,並且可能具有零個或多個數組元素型別的附加元素。例如,[number, ...string[]] 表示元組具有一個 number 元素,後跟任意數量的 string 元素。

示例
ts
function tuple<T extends any[]>(...args: T): T {
return args;
}
const numbers: number[] = getArrayOfNumbers();
const t1 = tuple("foo", 1, true); // [string, number, boolean]
const t2 = tuple("bar", ...numbers); // [string, ...number[]]

具有剩餘元素的元組型別的 length 屬性的型別為 number

新的 unknown 頂層型別

TypeScript 3.0 引入了一個新的頂層型別 unknownunknownany 的型別安全對應物。任何型別都可以賦值給 unknown,但如果不進行型別斷言或基於控制流的收窄,unknown 型別不能賦值給除了自身和 any 以外的任何型別。同樣,在未先斷言或收窄為更具體的型別之前,不允許對 unknown 進行任何操作。

示例
ts
// In an intersection everything absorbs unknown
type T00 = unknown & null; // null
type T01 = unknown & undefined; // undefined
type T02 = unknown & null & undefined; // null & undefined (which becomes never)
type T03 = unknown & string; // string
type T04 = unknown & string[]; // string[]
type T05 = unknown & unknown; // unknown
type T06 = unknown & any; // any
// In a union an unknown absorbs everything
type T10 = unknown | null; // unknown
type T11 = unknown | undefined; // unknown
type T12 = unknown | null | undefined; // unknown
type T13 = unknown | string; // unknown
type T14 = unknown | string[]; // unknown
type T15 = unknown | unknown; // unknown
type T16 = unknown | any; // any
// Type variable and unknown in union and intersection
type T20<T> = T & {}; // T & {}
type T21<T> = T | {}; // T | {}
type T22<T> = T & unknown; // T
type T23<T> = T | unknown; // unknown
// unknown in conditional types
type T30<T> = unknown extends T ? true : false; // Deferred
type T31<T> = T extends unknown ? true : false; // Deferred (so it distributes)
type T32<T> = never extends T ? true : false; // true
type T33<T> = T extends never ? true : false; // Deferred
// keyof unknown
type T40 = keyof any; // string | number | symbol
type T41 = keyof unknown; // never
// Only equality operators are allowed with unknown
function f10(x: unknown) {
x == 5;
x !== 10;
x >= 0; // Error
x + 1; // Error
x * 2; // Error
-x; // Error
+x; // Error
}
// No property accesses, element accesses, or function calls
function f11(x: unknown) {
x.foo; // Error
x[5]; // Error
x(); // Error
new x(); // Error
}
// typeof, instanceof, and user defined type predicates
declare function isFunction(x: unknown): x is Function;
function f20(x: unknown) {
if (typeof x === "string" || typeof x === "number") {
x; // string | number
}
if (x instanceof Error) {
x; // Error
}
if (isFunction(x)) {
x; // Function
}
}
// Homomorphic mapped type over unknown
type T50<T> = { [P in keyof T]: number };
type T51 = T50<any>; // { [x: string]: number }
type T52 = T50<unknown>; // {}
// Anything is assignable to unknown
function f21<T>(pAny: any, pNever: never, pT: T) {
let x: unknown;
x = 123;
x = "hello";
x = [1, 2, 3];
x = new Error();
x = x;
x = pAny;
x = pNever;
x = pT;
}
// unknown assignable only to itself and any
function f22(x: unknown) {
let v1: any = x;
let v2: unknown = x;
let v3: object = x; // Error
let v4: string = x; // Error
let v5: string[] = x; // Error
let v6: {} = x; // Error
let v7: {} | null | undefined = x; // Error
}
// Type parameter 'T extends unknown' not related to object
function f23<T extends unknown>(x: T) {
let y: object = x; // Error
}
// Anything but primitive assignable to { [x: string]: unknown }
function f24(x: { [x: string]: unknown }) {
x = {};
x = { a: 5 };
x = [1, 2, 3];
x = 123; // Error
}
// Locals of type unknown always considered initialized
function f25() {
let x: unknown;
let y = x;
}
// Spread of unknown causes result to be unknown
function f26(x: {}, y: unknown, z: any) {
let o1 = { a: 42, ...x }; // { a: number }
let o2 = { a: 42, ...x, ...y }; // unknown
let o3 = { a: 42, ...x, ...y, ...z }; // any
}
// Functions with unknown return type don't need return expressions
function f27(): unknown {}
// Rest type cannot be created from unknown
function f28(x: unknown) {
let { ...a } = x; // Error
}
// Class properties of type unknown don't need definite assignment
class C1 {
a: string; // Error
b: unknown;
c: any;
}

支援 JSX 中的 defaultProps

TypeScript 2.9 及更早版本未利用 JSX 元件內部的 React defaultProps 宣告。使用者通常必須將屬性宣告為可選,並在 render 中使用非空斷言,或者在匯出元件之前使用型別斷言來修復元件的型別。

TypeScript 3.0 在 JSX 名稱空間中增加了一個名為 LibraryManagedAttributes 的新類型別名。該輔助型別在對元件的 Props 型別使用 JSX 表示式進行檢查之前,對其定義了一個轉換;從而允許進行諸如以下自定義:如何處理提供的 props 與推斷的 props 之間的衝突、如何對映推斷、如何處理可選性以及如何組合來自不同位置的推斷。

簡而言之,使用此通用型別,我們可以模擬 React 在 defaultProps 以及某種程度上的 propTypes 等方面的特定行為。

tsx
export interface Props {
name: string;
}
export class Greet extends React.Component<Props> {
render() {
const { name } = this.props;
return <div>Hello {name.toUpperCase()}!</div>;
}
static defaultProps = { name: "world" };
}
// Type-checks! No type assertions needed!
let el = <Greet />;

注意事項

defaultProps 上使用顯式型別

預設屬性是從 defaultProps 屬性型別推斷出來的。如果添加了顯式型別註解,例如 static defaultProps: Partial<Props>;,編譯器將無法識別哪些屬性具有預設值(因為 defaultProps 的型別包含 Props 的所有屬性)。

請使用 static defaultProps: Pick<Props, "name">; 作為顯式型別註解,或者像上面的示例那樣不新增型別註解。

對於函式元件(以前稱為 SFC),請使用 ES2015 預設初始化程式。

tsx
function Greet({ name = "world" }: Props) {
return <div>Hello {name.toUpperCase()}!</div>;
}

@types/React 的更改

仍需要在 @types/React 中進行相應的更改,以將 LibraryManagedAttributes 定義新增到 JSX 名稱空間中。請記住,這存在一些侷限性。

/// <reference lib="..." /> 引用指令

TypeScript 增加了一個新的三斜槓引用指令 (/// <reference lib="name" />),允許檔案顯式包含現有的內建 lib 檔案。

內建 lib 檔案的引用方式與 tsconfig.json 中的 lib 編譯器選項相同(例如,使用 lib="es2015" 而不是 lib="lib.es2015.d.ts" 等)。

對於依賴內建型別(例如 DOM API 或內建 JS 執行時建構函式,如 SymbolIterable)的宣告檔案作者,建議使用三斜槓引用 lib 指令。以前,這些 .d.ts 檔案必須新增此類型別的向前/重複宣告。

示例

在編譯中的任意檔案中使用 /// <reference lib="es2017.string" /> 等同於使用 --lib es2017.string 進行編譯。

ts
/// <reference lib="es2017.string" />
"foo".padStart(4);

TypeScript 文件是一個開源專案。請提交 Pull Request 來幫助我們改進這些頁面 ❤

此頁面的貢獻者
MHMohamed Hegazy (53)
OTOrta Therox (13)
RCRyan Cavanaugh (2)
RIRuslan Iusupov (2)
EIEugene Ilyin (1)
11+

最後更新:2026 年 3 月 27 日