首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >巧用 TypeScript(三)

巧用 TypeScript(三)

作者头像
三毛
发布2018-12-14 11:14:21
1K0
发布2018-12-14 11:14:21
举报

数组与元组

创建一个数组很简单:

const arr = [1];
复制代码

此时 TypeScript 将会推断 arr 类型为 number[]

arr.push('1');  // Error
复制代码

当数组元素具有其它类型时,可以通过类型注解的方式:

const arr: Array<string | number> = [1];

arr.push('1');  // OK
arr.push(true);  // Error
复制代码

或者你也可以通过可选元组的方式:

const arr: [number, string?] = [1];         // arr 的成员类型可以是: number, string, undefined 
arr.push('1');   // OK
arr.push(true);   // Error
复制代码

使用元组形式,还能提供指定位置的类型检查:

arr[0] = '1';   // Error
arr[1] = 1;    // Error
复制代码

使用

通常,我们使用 Promise.all 并行发出多个请求:

interface A {
  name: string;
}

interface B {
  age: number;
}

const [{ data: a }, { data: b }] = await Promise.all([
  axios.get<A>('http://some.1'),
  axios.get<B>('http://some.2')
])
复制代码

此时,TypeScript 能推出 a 的类型是 A, b 的类型是 B

现在,稍作改变:当满足特定条件时,才发出第二个请求:

// 使用类型注解
const requestList: [Promise<AxiosResponse<A>>, Promise<AxiosResponse<B>>?]
                    = [axios.get<A>('http://some.1')];
if (flag) {
  requestList[1] = (axios.get<B>('http://some.2'));
};
const [ { data: a }, response ] = await Promise.all(requestList);
复制代码

我们期望它会如预想时那样工作,可是事与愿违,Promise.all(requestList),会出现类型兼容性的报错,在这个 Issues 里,描述了相同的问题。

现在,你可以通过断言的方式,来让程序正常运作:

const requestList: any[]  = [axios.get<A>('http://some.1')];  // 设置为 any[] 类型
if (flag) {
  requestList[1] = (axios.get<B>('http://some.2'));
}
const [
  { data: a },
  response
] = await Promise.all(requestList) as [AxiosResponse<A>, AxiosResponse<B>?] // 类型安全
复制代码

字面量类型

在 JavaScript 基础上,TypeScript 扩展了一系列字面量类型,用来确保类型的准确性。

如创建一个字符串字面量:

const a = 'hello';  // a 的类型是 'hello'
a = 'world';   // Error
复制代码

或者你也可以:

let a: 'hello' = 'hello';  // a 的类型是 'hello'
a = 'world';     // Error
复制代码

其它数据类型与此相似。

你也可以定义交叉类型与联合类型的字面量:

interface A {
  name: string;
}
interface B {
  name: string;
  age: number;
}

type C = A | B;
type D = A & B;
复制代码

对象字面量类型

对于对象字面量的类型,TypeScript 有一个被称之为 「Freshness 」的概念,它也被称为更严格的对象字面量检查,如下例子:

let someThing: { name: string };
someThing = { name: 'hello' };              // ok
someThine = { name: 'hello', age: 123 };    // Error, 对象字面量只能指定已知属性, { name: string } 类型中不存在 age 属性

let otherThing = { name: 'hello', age: 123 };
someThing = otherThing;                     // ok
复制代码

TypeScript 认为创建的每个对象字面量都是 「 fresh 」 状态;当一个 「 fresh 」 对象字面量赋值给一个变量时,如果对象的类型与变量类型不兼容时,会出现报错(如上例子中 someThine = { name: 'hello', age: 123 }; 的错误);当对象字面量的类型变宽,对象字面量的 「 fresh 」 状态会消失(如上例子中 someThing = otherThing; ,赋值以后,someThing 的类型变宽)。

一个更实际的用例如下:

function logName(something: { name: string }) {
  console.log(something.name);
}

const obj = {
  name: 'matt',
  job: 'being awesome'
}

logName(obj); // ok
logName({ name: 'matt' }); // ok
logName({ nama: 'matt' }); // Error: nama 属性在 { name: string } 属性中不存在。
logName({ name: 'matt', job: 'being awesome' }); // Error: 对象字面量只能指定已知属性,`job` 属性在这里并不存在。
复制代码

基本原理与上文中相似,当想用更严格的类型检查时,可以传一个具有 fresh 状态的对象字面量(如 logName({ name: 'matt', job: 'being awesome' });)。当你想多传一些属性至函数,可以将对象字面量赋值至一个新变量,然后再传至函数(如 logName(obj))。或者你也可以通过给函数形参添加多余类型的方式 function logName(someThing: { name: string; [key: string]: string })

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年11月18日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 数组与元组
    • 使用
    • 字面量类型
      • 对象字面量类型
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档