Array
const
斷言在本章中,我們將探討如何在 TypeScript 中輸入陣列。
陣列可以在 JavaScript 中扮演下列角色(其中一種或多種組合)
TypeScript 提供各種輸入陣列的方式,以容納這兩個角色。我們將接著探討這些方式。
Array
陣列類型文字包含元素類型,後接[]
。在以下程式碼中,陣列類型文字為string[]
// Each Array element has the type `string`:
: string[] = ['fee', 'fi', 'fo', 'fum']; const myStringArray
陣列類型文字是使用全域泛型介面類型Array
的簡寫
: Array<string> = ['fee', 'fi', 'fo', 'fum']; const myStringArray
如果元素類型較為複雜,我們需要為陣列類型文字加上括號
|string)[]
(number=> boolean)[] (()
泛型類型Array
在這種情況下會比較好
<number|string>
Array<() => boolean> Array
如果陣列有固定長度,且每個元素有不同的固定類型,取決於其位置,那麼我們可以使用元組類型字面值,例如 [string, string, boolean]
: [string, string, boolean] = ['oui', 'sí', true]; const yes
如果介面只有一個索引簽章,我們可以使用它來表示陣列
interface StringArray {: number]: string;
[index
}: StringArray = ['Huey', 'Dewey', 'Louie']; const strArr
同時具有索引簽章和屬性簽章的介面,僅適用於物件(因為索引元素和屬性需要同時定義)
interface FirstNamesAndLastName {: number]: string;
[index: string;
lastName
}
: FirstNamesAndLastName = {
const ducks0: 'Huey',
1: 'Dewey',
2: 'Louie',
: 'Duck',
lastName; }
由於陣列的兩個角色,TypeScript 無法總是猜測正確的類型。舉例來說,考慮以下陣列字面值,它被指定給變數 fields
: Fields = [
const fields'first', 'string', true],
['last', 'string', true],
['age', 'number', false],
[; ]
fields
的最佳類型是什麼?以下都是合理的選擇
type Fields = Array<[string, string, boolean]>;
type Fields = Array<[string, ('string'|'number'), boolean]>;
type Fields = Array<Array<string|boolean>>;
type Fields = [
string, string, boolean],
[string, string, boolean],
[string, string, boolean],
[; ]
type Fields = [
string, 'string', boolean],
[string, 'string', boolean],
[string, 'number', boolean],
[; ]
type Fields = [
<string|boolean>,
Array<string|boolean>,
Array<string|boolean>,
Array; ]
當我們使用非空陣列字面值時,TypeScript 的預設是推論清單類型(不是元組類型)
// %inferred-type: (string | number)[]
= [123, 'abc']; const arr
唉,這並不總是我們想要的
function func(p: [number, number]) {
;
return p
}// %inferred-type: number[]
= [1, 2];
const pair1
// @ts-expect-error: Argument of type 'number[]' is not assignable to
// parameter of type '[number, number]'. [...]
func(pair1);
我們可以透過在 const
宣告中新增類型註解來修正這個問題,這會避免類型推論
: [number, number] = [1, 2];
const pair2func(pair2); // OK
如果我們使用空陣列字面值初始化變數,那麼 TypeScript 最初會推論類型 any[]
,並在我們進行變更時逐步更新該類型
// %inferred-type: any[]
= [];
const arr1
.push(123);
arr1// %inferred-type: number[]
;
arr1
.push('abc');
arr1// %inferred-type: (string | number)[]
; arr1
請注意,最初推論的類型不受稍後發生的事情影響。
如果我們使用指定而不是 .push()
,事情會以相同的方式運作
// %inferred-type: any[]
= [];
const arr1
0] = 123;
arr1[// %inferred-type: number[]
;
arr1
1] = 'abc';
arr1[// %inferred-type: (string | number)[]
; arr1
相反地,如果陣列字面值至少有一個元素,那麼元素類型是固定的,並且不會在稍後變更
// %inferred-type: number[]
= [123];
const arr
// @ts-expect-error: Argument of type '"abc"' is not assignable to
// parameter of type 'number'. (2345)
.push('abc'); arr
const
斷言我們可以使用 const
斷言 為陣列字面值加上字尾
// %inferred-type: readonly ["igneous", "metamorphic", "sedimentary"]
=
const rockCategories 'igneous', 'metamorphic', 'sedimentary'] as const; [
我們宣告 rockCategories
不會變更。這有以下影響
陣列變成 readonly
– 我們無法使用會變更它的運算
// @ts-expect-error: Property 'push' does not exist on type
// 'readonly ["igneous", "metamorphic", "sedimentary"]'. (2339)
.push('sand'); rockCategories
TypeScript 推論一個元組。比較
// %inferred-type: string[]
= ['igneous', 'metamorphic', 'sedimentary']; const rockCategories2
TypeScript 推論字面值類型("igneous"
等),而不是更通用的類型。也就是說,推論的元組類型不是 [string, string, string]
。
以下是更多有和沒有 const
斷言的陣列字面值範例
// %inferred-type: readonly [1, 2, 3, 4]
= [1, 2, 3, 4] as const;
const numbers1 // %inferred-type: number[]
= [1, 2, 3, 4];
const numbers2
// %inferred-type: readonly [true, "abc"]
= [true, 'abc'] as const;
const booleanAndString1 // %inferred-type: (string | boolean)[]
= [true, 'abc']; const booleanAndString2
const
斷言的潛在陷阱const
斷言有兩個潛在陷阱。
首先,推論出的類型盡可能窄。這會對 let
宣告的變數造成問題:我們無法指定任何元組,除了我們用於初始化的元組
= [1, 2] as const;
let arr
= [1, 2]; // OK
arr
// @ts-expect-error: Type '3' is not assignable to type '2'. (2322)
= [1, 3]; arr
其次,透過 as const
宣告的元組無法變異
= [1, 2] as const;
let arr
// @ts-expect-error: Cannot assign to '1' because it is a read-only
// property. (2540)
1] = 3; arr[
這既不是優點也不是缺點,但我們需要知道它會發生。
每當我們透過索引存取陣列元素時,TypeScript 總是假設索引在範圍內(第 A 行)
: string[] = ['Hello'];
const messages
// %inferred-type: string
= messages[3]; // (A) const message
由於這個假設,message
的類型是 string
。而不是 undefined
或 undefined|string
,正如我們可能預期的。
如果我們使用元組類型,我們會收到錯誤
: [string] = ['Hello'];
const messages
// @ts-expect-error: Tuple type '[string]' of length '1' has no element
// at index '1'. (2493)
= messages[1]; const message
as const
會有相同的效應,因為它會導致推論出元組類型。