理解 TypeScript 中的“as const”
Understanding ‘as const’ in TypeScript
在 TypeScript 中使用as const
时,我们可以将对象的属性或数组的元素设置为readonly
,向语言表明表达式中的类型不会被扩大(例如 from 42
to
number
)。
索引.ts
function sum(a: number, b: number) { return a + b; } // 👇️ const arr: readonly [3, 4] const arr = [3, 4] as const; console.log(sum(...arr)); // 👉️ 7
我们创建了一个sum
将2
数字作为参数并返回总和的函数。
然而,我们在数组中有数字,所以我们需要一种方法来告诉 TypeScript 这个数组只能有
2
type 的元素。 number
这是在 TypeScript 中使用
const 断言的时候。
const 断言使我们能够告诉 TypeScript 数组的类型不会被扩大,例如 from [3, 4]
to number[]
。
示例中的数组变为readonly
元组,因此无法更改其内容,我们可以安全地在sum
函数调用中解压这两个数字。
如果您尝试更改数组的内容,则会出现错误。
索引.ts
function sum(a: number, b: number) { return a + b; } // 👇️ const arr: readonly [3, 4] const arr = [3, 4] as const; // ⛔️ ERROR: Property 'push' does not exist on type // 'readonly [3, 4]' arr.push(5);
我们使用了 const 断言,所以数组现在是一个readonly
元组,其内容无法更改,并且尝试这样做会在开发过程中导致错误。
如果我们尝试在sum
不使用 const 断言的情况下调用该函数,则会出现错误。
索引.ts
function sum(a: number, b: number) { return a + b; } // 👇️ const arr: readonly [3, 4] const arr = [3, 4]; // ⛔️ Error: A spread argument must either have a tuple // type or be passed to a rest parameter. console.log(sum(...arr)); // 👉️ 7
TypeScript 警告我们,没有办法知道变量的内容
在声明和
函数被调用arr
之间没有改变。sum()
当使用 const 断言时,数组变为只读元组,因此 TypeScript 可以确保其内容在声明和函数调用之间不会发生变化。
如果您不喜欢使用 TypeScript 的枚举结构,也可以使用 const 断言来替代枚举。
索引.ts
// 👇️ const Pages: {readonly home: '/'; readonly about: '/about'...} export const Pages = { home: '/', about: '/about', contacts: '/contacts', } as const;
如果您尝试更改对象的任何属性或添加新属性,您将收到错误消息。
索引.ts
// 👇️ const Pages: {readonly home: '/'; readonly about: '/about'...} export const Pages = { home: '/', about: '/about', contacts: '/contacts', } as const; // ⛔️ Error: Cannot assign to 'about', because it is // a read-only property Pages.about = 'hello'; // ⛔️ Error: Property 'test' does not exist on type ... Pages.test = 'hello';
然而,应该注意的是,const
上下文不会将表达式转换为完全不可变的。
索引.ts
const arr = ['/about', '/contacts']; // 👇️ const Pages: {readonly home: '/', menu: string[]} export const Pages = { home: '/', menu: arr, } as const; // ✅ Works Pages.menu.push('/test');
该menu
属性引用了一个外部数组,我们可以更改其内容。
如果数组是在对象上就地定义的,我们将无法更改其内容。
索引.ts
// 👇️ const Pages: {readonly home: '/', readonly menu: string[]} export const Pages = { home: '/', menu: ['/about'], } as const; // ⛔️ Error: Property 'push' does not exist on type // 'readonly ["/about"]' Pages.menu.push('/test');