做者:Valentino Gagliardihtml
译者:前端小智前端
来源:valentinogjava
官方网站的定义是:TypeScript 是 JS 类型的超集。它假设我们知道什么是超集,什么是类型化。为了简单起见,你能够将 TypeScript 看做是 JavaScript 之上的一个外壳。git
TypeScript
是一个外壳,由于编写 TypeScript 的代码,在编译以后,,剩下的只是简单的 JS 代码。github
可是 JS 引擎没法读取 TypeScript 代码,所以任何 TypeScript 文件都应该通过预翻译过程,即编译。只有在第一个编译步骤以后,才剩下纯 JS 代码,能够在浏览器中运行。稍后会介绍 TypeScript 编译是如何完成的。web
如今让咱们记住 TypeScript 是一种特殊的 JS,在浏览器中运行以前它须要一个翻译。正则表达式
刚开始,我们不彻底理解 TypeScript 为什么有意义。 你可能会问“ TypeScript 的目的是什么”。 这是一个很好的问题。typescript
实际上,一旦它在您的代码中发现严重和愚蠢的错误,你就会看到 TypeScript 的好处。更重要的是,TypeScript 会让代码变得结构良好并且仍是自动,这些还只是 TypeScript 的一小部分。express
无论怎样,也常常有人说 TypeScript 没用,太过笨拙。
凡事都有两面性,TypeScript 有不少反对者和支持者,但重要的是 TypeScript 是一个可靠的工具,将它放在我们的工具技能包中不会形成伤害。
为何配置? TypeScript 还有一个二进制文件,可将 TypeScript 代码编译为 JS 代码. 请记住,浏览器不理解 TypeScript:
mkdir typescript-tutorial && cd $_
npm init -y
复制代码
而后安装 TypeScript
npm i typescript --save-dev
复制代码
接下来在 package.json
中的 scripts
下添加以下内容,以便我们能够轻松地运行 TypeScript 编译器:
"scripts": {
"tsc": "tsc"
}
复制代码
tsc 表明 TypeScript 编译器,只要编译器运行,它将在项目文件夹中查找名为tsconfig.json 的文件。 使用如下命令为 TypeScript 生成配置文件:
npm run tsc -- --init
复制代码
执行成功后会在控制台收到 message TS6071: Successfully created a tsconfig.json file
。在项目文件夹中会看到新增了一个 tsconfig.json
文件。tsconfig。json
是一个可怕的配置文件,不要慌。我们不须要知道它的每个要点,在下一节中,会介绍入门的相关部分。
最好先初始化 git repo 并提交原始的 tsconfig.json,而后再打开文件。 咱们将只保留一些配置选项,并删除其余全部内容。 稍后,你可能须要将如今的版本与原始版本进行比较。
首先,请打开 tsconfig.json
并将全部原始内容替换为如下内容:
{
"compilerOptions": {
"target": "es5",
"strict": true
}
}
复制代码
保存并关闭文件。 首先,你可能想知道 tsconfig.json 是干什么的。 该配置文件由 TypeScript 编译器和任何具备 TypeScript 支持的代码编辑器读取。
noImplicitAny true
:当变量没有定义类型时,TypeScript 会报错
alwaysStrict true:严格模式是 JS 的安全机制,它能够防止意外的全局变量,默认的 this
绑定等。 设置为 “alwaysStrict
” 时,TypeScript 在每一个KS 文件的顶部都使用 “use strict”
。
有更多的配置选项可用。随着时间的推移,你会学到更多,由于如今上面的两个选择是你开始学习时须要知道的一切。
TypeScript 支持与 JS 几乎相同的数据类型,此外,TypeScript 本身添加了更多的类型,如 any
类型同样。
“any”
是松散的 TypeScript 类型。 这意味着:此变量能够是任何类型:字符串,布尔值,对象等。 实际上,这就像根本没有类型检查。
我们从一个合法的 KS函数开始:filterByTerm。在项目文件夹中建立一个名为 filterByTerm.js 的新文件,并输入如下内容
function filterByTerm(input, searchTerm) {
if (!searchTerm) throw Error("searchTerm 不能为空");
if (!input.length) throw Error("input 不能为空");
const regex = new RegExp(searchTerm, "i");
return input.filter(function(arrayElement) {
return arrayElement.url.match(regex);
});
}
filterByTerm("input string", "java");
复制代码
若是如今不了解逻辑,请不要担忧。 看一下该函数的参数,以及几行以后如何使用它们。 只需查看代码,就应该已经发现了问题。
我想知道是否有一种方法能够在个人 IDE 中检查这个函数,而不须要运行代码或者用Jest测试它。这可能吗? TypeScript 在这方面作得很好,实际上它是 JS 中静态检查的最佳工具,也就是说,在代码运行以前测试代码的正确性。
所以,我们改用 TypeScript ,将文件的扩展名从 filterByTerm.js 改成 filterByTerm.ts。经过这种更改,你会发现代码中的一堆错误
能够看到函数参数下的有不少红色标记。从如今开始,会向你展现文本形式的错误,可是请记住,当我们在TypeScript 中出错时,IDE 和文本编辑器都会显示这些红线。
肯定哪一个地方错:
npm run tsc
复制代码
能够看到控制的报错:
filterByTerm.ts:1:23 - error TS7006: Parameter 'input' implicitly has an 'any' type.
1 function filterByTerm(input, searchTerm) {
~~~~~
filterByTerm.ts:1:30 - error TS7006: Parameter 'searchTerm' implicitly has an 'any' type.
1 function filterByTerm(input, searchTerm) {
~~~~~~~~~~
filterByTerm.ts:5:32 - error TS7006: Parameter 'arrayElement' implicitly has an 'any' type.
5 return input.filter(function(arrayElement) {
复制代码
TypeScript 告诉你函数参数具备 “any”
类型,若是还记得的话,它能够是 TypeScript 中的 any
类型。 咱们须要在咱们的 TypeScript 代码中添加适当的类型注释。
到目前为止,JS 有七种类型
除了 Object 类型外,其它是 JS 的基本数据类型。每种 JS 类型都有相应的表示,能够代码中使用,好比字符串和数字
var name = "Hello John";
var age = 33;
复制代码
JS 的问题是,变量能够随时更改其类型。例如,布尔值能够变成字符串(将如下代码保存到名为 types.js 的文件中)
var aBoolean = false;
console.log(typeof aBoolean); // "boolean"
aBoolean = "Tom";
console.log(typeof aBoolean); // "string"
复制代码
转换能够是有意的,开发人员可能真的但愿将 Tom
分配到 aBoolean
,可是这类错误极可能是偶然发生的。
从技术上讲,JS 自己没有什么问题,由于它的类型动态是故意的。JS 是做为一种简单的 web 脚本语言而诞生的,而不是做为一种成熟的企业语言。
然而,JS 松散的特性可能会在你的代码中形成严重的问题,破坏其可维护性。TypeScript 旨在经过向 JS 添增强类型来解决这些问题。实际上,若是将 types.js 的扩展更改成 types.ts 。你会在IDE中看到 TypeScript 的抱怨。
types.ts
的编译控制台会报错:
types.ts:4:1 - error TS2322: Type '"Tom"' is not assignable to type 'boolean'.
复制代码
有了这些知识,接着,我们更深刻地研究 TypeScript 类型。
TypeScript 强调有类型,我们上面的代码根本没有类型,是时候添加一些了。首先要修正函数参数。经过观察这个函数是如何调用的,它彷佛以两个字符串做为参数:
filterByTerm("input string", "java");
复制代码
为参数添加类型:
function filterByTerm(input: string, searchTerm: string) {
// ...
}
// ...
复制代码
接着编译:
npm run tsc
复制代码
剩下的错误:
filterByTerm.ts:5:16 - error TS2339: Property 'filter' does not exist on type 'string'.
复制代码
能够看到 TypeScript 是如何指导咱们,如今的问题在于 filter
方法。
function filterByTerm(input: string, searchTerm: string) {
// 省略一些
return input.filter(function(arrayElement) {
return arrayElement.url.match(regex);
});
}
复制代码
我们告诉 TypeScript “input”
是一个字符串,可是在后面的代码中调用了 filter
方法,它属于数组。咱们真正须要的是将输入标记为某个东西的数组,多是字符串数组:
为此,有两个选择。选项1:string[]
function filterByTerm(input: string[], searchTerm: string) {
// ...
}
复制代码
选项2: Array<Type>
function filterByTerm(input: Array<string>, searchTerm: string) {
// ...
}
复制代码
我我的更喜欢选项2。 如今,尝试再次编译(npm run tsc
),控制台信息以下:
filterByTerm.ts:10:14 - error TS2345: Argument of type '"input string"' is not assignable to parameter of type 'string[]'.
filterByTerm("input string", "java");
复制代码
TypeScript 还会校验传入的类型。 咱们将 input
改成字符串数组:
filterByTerm(["string1", "string2", "string3"], "java");
复制代码
这是到目前为止的完整代码:
function filterByTerm(input: Array<string>, searchTerm: string) {
if (!searchTerm) throw Error("searchTerm 不能为空");
if (!input.length) throw Error("input 不能为空");
const regex = new RegExp(searchTerm, "i");
return input.filter(function(arrayElement) {
return arrayElement.url.match(regex);
});
}
filterByTerm(["string1", "string2", "string3"], "java");
复制代码
看上去很好,可是,编译(npm run tsc)仍是过不了:
filterByTerm.ts:6:25 - error TS2339: Property 'url' does not exist on type 'string'.
复制代码
TypeScript 确实很严谨。 咱们传入了一个字符串数组,可是在代码后面,尝试访问一个名为 “url”
的属性:
return arrayElement.url.match(regex);
复制代码
这意味着我们须要一个对象数组,而不是字符串数组。我们在下一节中解决这个问题。
上面遗留一个问题:由于 filterByTerm
被传递了一个字符串数组。url
属性在类型为 string
的TypeScript 上不存在。因此我们改用传递一个对象数组来解决这个问题:
filterByTerm(
[{ url: "string1" }, { url: "string2" }, { url: "string3" }],
"java"
);
复制代码
函数定义也要对应的更改:
function filterByTerm(input: Array<object>, searchTerm: string) {
// omitted
}
复制代码
如今让咱们编译代码
npm run tsc
复制代码
控制输出:
filterByTerm.ts:6:25 - error TS2339: Property 'url' does not exist on type 'object'.
复制代码
又来了,通用 JS 对象没有任何名为 url
的属性。对我来讲,TypeScript 对类型要求真的是很严谨。
这里的问题是,我们不能给一个随机对象分配属性,TypeScript 的核心原则之一是对值所具备的结构进行类型检查, 在 TypeScript 里,接口(interface)的做用就是为这些类型命名和为你的代码或第三方代码定义契约,我们可使用接口来解决这个问题。
经过查看咱们的代码,咱们能够想到一个名为 Link
的简单**"模型"**,其结构应该符合如下模式:它必须有一个类型为 string
的 url
属性。
在TypeScript 中,你能够用一个接口来定义这个模型,就像这样(把下面的代码放在 filterByTerm.ts 的顶部):
interface ILink {
url: string;
}
复制代码
对于接口声明,这固然不是有效的 JS 语法,在编译过程当中会被删除。
提示:在定义接口名字前面加上大写的I
,这是 TypeScript 的惯例。
如今,使用使用接口 ILink
定义 input
类型
function filterByTerm(input: Array<ILink>, searchTerm: string) {
// ...
}
复制代码
经过此修复,能够说 TypeScript “指望 ILink 数组”做为该函数的输入,如下是完整的代码:
interface ILink {
url: string;
}
function filterByTerm(input: Array<ILink>, searchTerm: string) {
if (!searchTerm) throw Error("searchTerm 不能为空");
if (!input.length) throw Error("input 不能为空");
const regex = new RegExp(searchTerm, "i");
return input.filter(function(arrayElement) {
return arrayElement.url.match(regex);
});
}
filterByTerm(
[{ url: "string1" }, { url: "string2" }, { url: "string3" }],
"java"
);
复制代码
此时,全部的错误都应该消失了,能够运行了:
npm run tsc
复制代码
编译后,会在项目文件夹中生成一个名为 filterByTerm.js 的文件,其中包含纯 JS 代码。能够检出该文件并查看 TypeScript 特定的声明最终转换成 JS 的是什么样的。
由于 alwaysStrict
设置为 true
,因此 TypeScript 编译器也会在 filterByTerm.js 的顶部使用 use strict
。
TypeScript 接口是该语言最强大的结构之一。接口有助于在整个应用程序中造成模型,这样任何开发人员在编写代码时均可以选择这种模型并遵循它。
前面,我们定义了一个简单的接口 ILink
interface ILink {
url: string;
}
复制代码
若是您想要向接口添加更多的字段,只需在块中声明它们便可:
interface ILink {
description: string;
id: number;
url: string;
}
复制代码
如今,类型为ILink
的对象都必须实现新字段,不然就会出现错误,若是把上面 的定义从新写入 filterByTerm.ts 而后从新编译就会报错了:
filterByTerm.ts:17:4 - error TS2739: Type '{ url: string; }' is missing the following properties from type 'ILink': description, id
复制代码
问题在于咱们函数的参数:
filterByTerm(
[{ url: "string1" }, { url: "string2" }, { url: "string3" }],
"java"
);
复制代码
TypeScript 能够经过函数声明来推断参数是 ILink
的类型数组。所以,该数组中的任何对象都必须实现接口 ILink 中定义的全部字段
大多数状况下,实现全部字段是不太现实的。毕竟,咱也不知道 ILink
类型的每一个新对象是否会须要拥有全部字段。不过不要担忧,要使编译经过,能够声明接口的字段可选,使用 ?
表示:
interface ILink {
description?: string;
id?: number;
url: string;
}
复制代码
如今编辑器和编译器都没问题了。然而 TypeScript 接口能够作的更多,在下一节咱们将看到如何扩展它们。但首先简要介绍一下 TypeScript 中的变量。
到目前为止,我们已经了解了如何向函数参数中添加类型:
function filterByTerm(input: Array<ILink>, searchTerm: string) {
//
}
复制代码
TypeScript 并不限于此,固然也能够向任何变量添加类型。为了说明这个例子,我们一一地提取函数的参数。首先咱要提取每个单独的对象:
const obj1: ILink = { url: "string1" };
const obj2: ILink = { url: "string2" };
const obj3: ILink = { url: "string3" };
复制代码
接下来咱们能够像这样定义一个 ILink
数组:
const arrOfLinks: Array<ILink> = [obj1, obj2, obj3];
复制代码
参数 searchTerm
对应的类型能够这样:
const term: string = "java";
复制代码
如下是完整的代码:
interface ILink {
description?: string;
id?: number;
url: string;
}
function filterByTerm(input: Array<ILink>, searchTerm: string) {
if (!searchTerm) throw Error("searchTerm 不能为空");
if (!input.length) throw Error("input 不能为空");
const regex = new RegExp(searchTerm, "i");
return input.filter(function(arrayElement) {
return arrayElement.url.match(regex);
});
}
const obj1: ILink = { url: "string1" };
const obj2: ILink = { url: "string2" };
const obj3: ILink = { url: "string3" };
const arrOfLinks: Array<ILink> = [obj1, obj2, obj3];
const term: string = "java";
filterByTerm(arrOfLinks, term);
复制代码
与 JS 相比,TypeScript看起来更冗长,有时甚至是多余的。可是随着时间的推移,会发现添加的类型越多,代码就越健壮。
经过添加类型注释,对 TypeScript 的了解也越多,还能够帮助你更好地理解代码的意图。
例如,arrOfLinks
与正确的类型(ILink
的数组)相关联,我们编辑器就能够推断出数组中的每一个对象都有一个名为url
的属性,如接口 ILink
中所定义:
除了字符串、数组和数字以外,TypeScript 还有更多类型。有 boolean
,tuple (元组),any, never,enum
。若是你感兴趣,能够查看文档。
如今,我们继续扩展接口。
TypeScript 接口很好。可是,若是哪天我们须要一个新的对象,所需的类型跟如今有接口基本差很少。假设咱们须要一个名为 IPost
的新接口,它具备如下属性:
该接口的字段其中有些,咱们 ILink
接口都有了。
interface ILink {
description?: string;
id?: number;
url: string;
}
复制代码
是否有办法重用接口 ILink ? 在 TypeScript 中,可使用继承来扩展接口,关键字用 extends 表示:
interface ILink {
description?: string;
id?: number;
url: string;
}
interface IPost extends ILink {
title: string;
body: string;
}
复制代码
如今,IPost
类型的对象都将具备可选的属性 description
、id
、url
和必填的属性 title
和body
:
interface ILink {
description?: string;
id?: number;
url: string;
}
interface IPost extends ILink {
title: string;
body: string;
}
const post1: IPost = {
description:
"TypeScript tutorial for beginners is a tutorial for all the JavaScript developers ...",
id: 1,
url: "www.valentinog.com/typescript/",
title: "TypeScript tutorial for beginners",
body: "Some stuff here!"
};
复制代码
当像 post1
这样的对象使用一个接口时,咱们说 post1
实现了该接口中定义的属性。
扩展接口意味着借用其属性并扩展它们以实现代码重用。固然 TypeScript 接口还也能够描述函数,稍后会看到。
JS 对象是键/值对的容器。 以下有一个简单的对象:
const paolo = {
name: "Paolo",
city: "Siena",
age: 44
};
复制代码
咱们可使用点语法访问任何键的值:
console.log(paolo.city);
复制代码
如今假设键是动态的,咱们能够把它放在一个变量中,而后在括号中引用它
const paolo = {
name: "Paolo",
city: "Siena",
age: 44
};
const key = "city";
console.log(paolo[key]);
复制代码
如今我们添加另外一个对象,将它们都放到一个数组中,并使用filter
方法对数组进行筛选,就像咱们在 filterByTerm.js 中所作的那样。但这一次键是动态传递的,所以能够过滤任何对象键:
const paolo = {
name: "Paolo",
city: "Siena",
age: 44
};
const tom = {
name: "Tom",
city: "Munich",
age: 33
};
function filterPerson(arr, term, key) {
return arr.filter(function(person) {
return person[key].match(term);
});
}
filterPerson([paolo, tom], "Siena", "city");
复制代码
这是比较重要的一行行:
return person[key].match(term);
复制代码
能行吗 是的,由于 JS 不在意 paolo
或 tom
是否可经过动态 [key]
进行“索引化”。 那在 TS 又是怎么样的呢?
在下一部分中,咱们将使用动态键使 filterByTerm
更加灵活。
让咱们回到 filterByTerm.ts 中 filterByTerm 函数
function filterByTerm(input: Array<ILink>, searchTerm: string) {
if (!searchTerm) throw Error("searchTerm 不能为空");
if (!input.length) throw Error("input 不能为空");
const regex = new RegExp(searchTerm, "i");
return input.filter(function(arrayElement) {
return arrayElement.url.match(regex);
});
}
复制代码
它看起来不那么灵活,由于对于每一个 ILink
,我们都使用硬编码方式将属性 url
与正则表达式相匹配。咱们但愿使动态属性(也就是键)让代码更灵活:
function filterByTerm(
input: Array<ILink>,
searchTerm: string,
lookupKey: string = "url"
) {
if (!searchTerm) throw Error("searchTerm 不能为空");
if (!input.length) throw Error("input 不能为空");
const regex = new RegExp(searchTerm, "i");
return input.filter(function(arrayElement) {
return arrayElement[lookupKey].match(regex);
});
}
复制代码
lookupKey
是动态键,这是给它分配了默认参数 “url”
。 接着编译代码:
npm run tsc
复制代码
固然会报错:
error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'ILink'.
No index signature with a parameter of type 'string' was found on type 'ILink'.
复制代码
出错行:
return arrayElement[lookupKey].match(regex);
复制代码
元素隐式具备 "any"
类型,由于类型 “ILink” 没有索引签名,须要你添加一个索引到对象的接口,这很容易解决。
转到接口 ILink 并添加索引:
interface ILink {
description?: string;
id?: number;
url: string;
[index: string] : string
}
复制代码
语法有点奇怪,但相似于对象上的动态键访问。这意味着咱们能够经过类型为 string
的索引访问该对象的任何键,该索引反过来又返回另外一个字符串。
不过,这样写会引起其它错误:
error TS2411: Property 'description' of type 'string | undefined' is not assignable to string index type 'string'.
error TS2411: Property 'id' of type 'number | undefined' is not assignable to string index type 'string'.
复制代码
这是由于接口上的一些属性是可选的,多是 undefined
,并且返回类型不老是string
(例如,id 是一个 number
)。
interface ILink {
description?: string;
id?: number;
url: string;
[index: string]: string | number | undefined;
}
复制代码
这一行:
[index: string]: string | number | undefined;
复制代码
表示该索引是一个字符串,能够返回另外一个字符串、数字或 undefined
。尝试再次编译,这里有另外一个错误
error TS2339: Property 'match' does not exist on type 'string | number'.
return arrayElement[lookupKey].match(regex);
复制代码
报的没毛病。match 方法只存在字符串中 ,并且咱们的索引有可能返回一个 number
。为了修正这个错误,咱们可使用 any
类型:
interface ILink {
description?: string;
id?: number;
url: string;
[index: string]: any;
}
复制代码
再次编译经过。
到目前为止有不少新东西。如今来看看 TypeScript 的另外一个有用的特性**:函数的返回类型**。
回到 filterByTerm
函数:
function filterByTerm(
input: Array<ILink>,
searchTerm: string,
lookupKey: string = "url"
) {
if (!searchTerm) throw Error("searchTerm 不能为空");
if (!input.length) throw Error("input 不能为空");
const regex = new RegExp(searchTerm, "i");
return input.filter(function(arrayElement) {
return arrayElement[lookupKey].match(regex);
});
}
复制代码
若是按原样调用,传递前面看到的 ILink 数组和搜索词string3
,则如预期的那样返回一个对象数组:
filterByTerm(arrOfLinks, "string3");
// EXPECTED OUTPUT:
// [ { url: 'string3' } ]
复制代码
但如今考虑一个更改的变体:
function filterByTerm(
input: Array<ILink>,
searchTerm: string,
lookupKey: string = "url"
) {
if (!searchTerm) throw Error("searchTerm cannot be empty");
if (!input.length) throw Error("input cannot be empty");
const regex = new RegExp(searchTerm, "i");
return input
.filter(function(arrayElement) {
return arrayElement[lookupKey].match(regex);
})
.toString();
}
复制代码
若是如今调用,使用相同的 ILink
数组和搜索词 string3
,它将返回 [object object]
filterByTerm(arrOfLinks, "string3");
// WRONG OUTPUT:
// [object Object]
复制代码
该函数没有按照预期工做,若是对 JS 隐式类型转换不清楚就很难发现问题。幸运的是,TypeScript 能够捕获这些错误,就像你在编辑器中写的那样。
修正以下:
function filterByTerm(/* 省略 */): Array<ILink> {
/* 省略 */
}
复制代码
它是如何工做的? 经过在函数体以前添加类型注释,告诉 TypeScript 指望另外一个数组做为返回值。如今这个bug 很容易被发现。
interface ILink {
description?: string;
id?: number;
url: string;
[index: string]: any;
}
function filterByTerm(
input: Array<ILink>,
searchTerm: string,
lookupKey: string = "url"
): Array<ILink> {
if (!searchTerm) throw Error("searchTerm cannot be empty");
if (!input.length) throw Error("input cannot be empty");
const regex = new RegExp(searchTerm, "i");
return input
.filter(function(arrayElement) {
return arrayElement[lookupKey].match(regex);
})
.toString();
}
const obj1: ILink = { url: "string1" };
const obj2: ILink = { url: "string2" };
const obj3: ILink = { url: "string3" };
const arrOfLinks: Array<ILink> = [obj1, obj2, obj3];
filterByTerm(arrOfLinks, "string3");
复制代码
如今编译并检查错误:
error TS2322: Type 'string' is not assignable to type 'ILink[]'.
复制代码
我们但愿返回值的是 ILink
数组,而不是字符串。要修复此错误,从末尾删除 .tostring()
并从新编译代码就好了。
到目前为止,咱们已经将接口视为描述对象和自定义类型的工具。可是经过其余人的代码,你可能也注意到了关键字的 type。
显然,interface 和 type 在 TypeScript 中能够互换使用,可是它们在许多方面有所不一样,这就是TypeScript 给初学者的困惑。
请记住: TypeScript 中的接口描述是某个东西的结构,大多数状况下是一个复杂的对象。
另外一方面,type
也能够用来描述自定义的结构,但它只是一个别名,或者换句话说,是自定义类型的标签。例如,设想一个有两个字段的接口,其中一个是布尔型、数字型和字符串型的联合类型。
interface IExample {
authenticated: boolean | number | string;
name: string;
}
复制代码
例如,使用 type 别名 能够提取自定义联合类型,并建立名为 Authenticated 的标签
type Authenticated = boolean | number | string;
interface IExample {
authenticated: Authenticated;
name: string;
}
复制代码
经过这种方式,咱能够隔离所作的更改,就没必要在整个代码库中复制/粘贴 联合类型。
若是要将 type 应用上面示例(filterByTerm
),建立一个名为 ILinks 的新标签,并将 Array 分配给它。 这样,就能够引用前者:
// the new label
type ILinks = Array<ILink>;
// the new label
function filterByTerm(
input: ILinks,
searchTerm: string,
lookupKey: string = "url"
): ILinks {
if (!searchTerm) throw Error("searchTerm 不能为空");
if (!input.length) throw Error("input 不能为空");
const regex = new RegExp(searchTerm, "i");
return input.filter(function(arrayElement) {
return arrayElement[lookupKey].match(regex);
});
}
const obj1: ILink = { url: "string1" };
const obj2: ILink = { url: "string2" };
const obj3: ILink = { url: "string3" };
const arrOfLinks: ILinks = [obj1, obj2, obj3];
filterByTerm(arrOfLinks, "string3");
复制代码
固然,这不是 type
用法最好事例。那么在 interface 和 type 之间使用哪一个呢? 我更喜欢复杂对象的接口。TypeScript 文档 也建议了。
一个软件的理想状态是能够扩展,所以,若是可能,应始终在类型别名上使用接口。
函数是 JS 中的一等公民,而对象是该语言中最重要的实体。
对象大可能是键/值对的容器,它们也能够保存函数,这一点也不奇怪。当一个函数位于一个对象内部时,它能够经过关键字 this
访问“宿主”对象:
const tom = {
name: "前端小智",
city: "厦门",
age: 26,
printDetails: function() {
console.log(`${this.name} - ${this.city}`);
}
};
复制代码
到目前为止,我们已经看到 TypeScript 接口应用于简单对象,用于描述字符串和数字。 可是他们能够作的更多。 举个例, 使用如下代码建立一个名为 interfaces-functions.ts 的新文件:
const tom = {
name: "前端小智",
city: "厦门",
age: 26,
printDetails: function() {
console.log(`${this.name} - ${this.city}`);
}
};
复制代码
这是一个 JS 对象,我们使用接口 IPerson 给它加上类型:
interface IPerson {
name: string;
city: string;
age: number;
}
const tom: IPerson = {
name: "前端小智",
city: "厦门",
age: 26,
printDetails: function() {
console.log(`${this.name} - ${this.city}`);
}
};
复制代码
编译代码并查看报错信息:
interfaces-functions.ts:11:3 - error TS2322: Type '{ name: string; city: string; age: number; printDetails: () => void; }' is not assignable to type 'IPerson'.
Object literal may only specify known properties, and 'printDetails' does not exist in type 'IPerson'.
复制代码
IPerson 没有任何名为printDetails
的属性,但更重要的是它应该是一个函数。幸运的是,TypeScript 接口也能够描述函数。以下所示:
interface IPerson {
name: string;
city: string;
age: number;
printDetails(): void;
}
复制代码
在这里,咱们添加了类型函数的属性 printDetails
,返回 void
。 void
表示不返回任何值。
实际上,打印到控制台的函数不会返回任何内容。 若是要从 printDetails
返回字符串,则能够将返回类型调整为 string
:
interface IPerson {
name: string;
city: string;
age: number;
printDetails(): string;
}
const tom: IPerson = {
name: "前端小智",
city: "厦门",
age: 26,
printDetails: function() {
return `${this.name} - ${this.city}`;
}
};
复制代码
若是函数有参数呢? 在接口中,能够为它们添加类型注释
interface IPerson {
name: string;
city: string;
age: number;
printDetails(): string;
anotherFunc(a: number, b: number): number;
}
复制代码
代码部署后可能存在的BUG无法实时知道,过后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给你们推荐一个好用的BUG监控工具 Fundebug。
原文:www.valentinog.com/blog/typesc…
这里没法涵盖每个 TypeScript 特性。例如,省略了ES2015类及其与接口或更高级类型(如 Partial )的关系。固然后续会持续介绍。
在这个 TypeScript 教程中,讲了:
TS 帮助我们减小一些 JS 代码隐藏的错误。须要重复的是,TypeScript 不能替代测试。 蛤它确实是一个有价值的工具,一开始很难掌握,但彻底值得投资。
阿(a)里(li)云(yun)最近在作活动,低至2折,有兴趣能够看看:promotion.aliyun.com/ntms/yunpar…
干货系列文章汇总以下,以为不错点个Star,欢迎 加群 互相学习。
由于篇幅的限制,今天的分享只到这里。若是你们想了解更多的内容的话,能够去扫一扫每篇文章最下面的二维码,而后关注我们的微信公众号,了解更多的资讯和有价值的内容。
每次整理文章,通常都到2点才睡觉,一周4次左右,挺苦的,还望支持,给点鼓励