基本数据类型 string、number、boolean
- TS 并不区分
int或者float,所有与数相关的类型统一为number。所以 1, 2, 3, 4, 5 是number,3.1415926535 也是nubmer。 const和let语法的区别:const为绑定(binding)变量与值的映射关系不可变;let绑定可变变量与值的映射关系可被重新指定。真正区别在于“能不能重新赋值”,而不是“值本身变不变”。一般而言,默认全用const,除非明确需要重新赋值时才用let。- 在比较老的 JS 版本里,仅支持
var语法,而不支持const和let语法。
变量类型注释
const varName[: type] [= value];
// e.g.
const myName: string = "Alice";
const fruit = "apple";
const myAge number;
const whatever: any;
Tips:
const fruit = "apple";:TypeScript 会尽可能自动推断你的代码中的类型。例如,变量的类型是根据其初始值的类型推断的。在这个例子中fruit的类型会被推断为string。const myAge number;TS 允许显式声明变量类型,后面需要的时候再赋值。const whatever: any;:如果不想对数据类型进行校验,可以指定类型为any。
若想知道某变量的类型,可以使用类型运算符(typeof、instanceof)。
typeof 是一元运算符,返回操作数的数据类型。
const num = 12
// output: number
console.log(typeof num);
instanceof 运算符用于判断对象是否为指定的类型,后面章节我们会具体介绍它。
定义联合类型 Union Type
你可能看到的组合类型的第一种方式是联合类型。联合类型是由两个或多个其他类型组成的类型,表示这些类型中任何一个的值。我们将这些类型中的每一个称为联合的成员。
function printId(id: number | string) {
console.log("Your ID is: " + id);
}
printId(101); // OK
printId("202"); // OK
printId({ myID: 22342 });
// Error!!!
// Argument of type '{ myID: number; }'
// is not assignable to parameter of type 'string | number'.
联合成员的分隔符允许在第一个元素之前,所以你也可以这样写:
function printTextOrNumberOrBool(
textOrNumberOrBool:
| string
| number
| boolean
) {
console.log(textOrNumberOrBool);
}
且 TypeScript 只会在操作对联合的每个成员都有效时才允许该操作。例如,如果你有联合类型 string | number ,你不能使用仅在 string 上可用的方法:
function printId(id: number | string) {
console.log(id.toUpperCase());
// Property 'toUpperCase' does not exist on type 'string | number'.
// Property 'toUpperCase' does not exist on type 'number'.
}
解决方案是通过代码来缩小联合类型,这与在 JavaScript 中不使用类型注解时的情况相同。当 TypeScript 能够根据代码的结构推断出一个更具体的类型时,就会发生缩小。例如,TypeScript 知道只有 string 值会有 typeof 值 string:
function printId(id: number | string) {
if (typeof id === "string") {
// In this branch, id is of type 'string'
console.log(id.toUpperCase());
} else {
// Here, id is of type 'number'
console.log(id);
}
}
枚举类型 Enum Type
枚举类型是拓展类型,JS 中没有枚举这种数据类型。
枚举允许开发者定义一组命名的常量。使用枚举可以使文档意图更加清晰,或创建一组不同的案例。TypeScript 提供了数值型和基于字符串的枚举。(理论上来说不一定非要将枚举内的类型统一,但异构枚举会让对枚举值的处理变麻烦,基本上不会使用)。
◾数值型枚举
enum Direction {
Up = 1,
Down,
Left,
Right,
}
这里对初始值进行了初始化,且TS会自动推断枚举值的 value,例如上面的例子中,指定 UP = 1,那么 Down、Left、Right 的值会被推断为 2,3,4。如果指定 UP = 0,那么其他枚举值会顺次被推断为 1,2,3。
🤪 Question:如果
UP = 1的同时Down =3。那么Left的值会是多少呢?
◾字符串枚举
字符串枚举是一个类似的概念,但在运行时有细微的差别,如下文所述。在字符串枚举中,每个成员必须使用字符串字面量或另一个字符串枚举成员进行常量初始化(毕竟字符串可没法儿进行“推断”)。
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}
TypeScript 主要包含以下几种运算:
1. 算术运算符
2. 逻辑运算符
3. 关系运算符
4. 位运算符
5. 赋值运算符
6. 三元/条件运算符
7. 负号运算符
8. 字符串运算符
9. 类型运算符
运算符
TypeScript 继承自 JavaScript,因此运算符行为与 JS 一致。
| 类别 | 运算符 | 名称 / 含义 | 说明 | 示例 (x=7, y=5) |
|---|---|---|---|---|
| 算术运算符 | + |
加法 | 数值相加或字符串拼接 | x = y + 2 → x = 7 |
- |
减法 | 左操作数减右操作数 | x = y - 2 → x = 3 |
|
* |
乘法 | 两数相乘 | x = y * 2 → x = 10 |
|
/ |
除法 | 返回浮点商(即使整除也可能是小数) | x = y / 2 → x = 2.5 |
|
% |
取模(求余) | 返回除法的余数 | x = y % 2 → x = 1 |
|
++ |
自增 | 值加 1;前缀 (++y) 先加后返回,后缀 (y++) 先返回后加 |
x = y++ → x = 5, y = 6 |
|
-- |
自减 | 值减 1;前缀 (--y) 先减后返回,后缀 (y--) 先返回后减 |
x = y-- → x = 5, y = 4 |
|
- |
负号(一元减) | 取数值的相反数 | x = -y → x = -5 |
|
+ |
正号(一元加) | 尝试将操作数转为数字(常用于字符串转数字) | x = +"5" → x = 5 |
|
| 关系运算符 | == |
相等(宽松) | 比较前会进行类型转换 | 5 == "5" → true |
=== |
严格相等 | 类型和值都必须相同 | 5 === "5" → false |
|
!= |
不等(宽松) | !(a == b) |
5 != "6" → true |
|
!== |
严格不等 | !(a === b) |
5 !== "5" → true |
|
> |
大于 | (x > y) → true |
||
< |
小于 | (x < y) → false |
||
>= |
大于等于 | (x >= y) → true |
||
<= |
小于等于 | (x <= y) → false |
||
| 逻辑运算符 | && |
逻辑与 | 若左为真则返回右,否则返回左(短路求值)??? | (x<10 && y>1) → true |
| ` | ` | 逻辑或 | ||
! |
逻辑非 | 取反布尔值 | !(x == y) → true |
|
| 位运算符 | & |
按位与 | 对两个数的二进制位逐位 AND | 5 & 1 → 1 |
| ` | ` | 按位或 | 逐位 OR | |
^ |
按位异或 | 逐位 XOR(不同为 1) | 5 ^ 1 → 4 |
|
~ |
按位取反 | 一元运算,翻转所有位(结果为 -(x+1)) | ~5 → -6 |
|
<< |
左移 | 二进制左移,低位补 0 | 5 << 1 → 10 |
|
>> |
算术右移(有符号) | 保留符号位,高位补符号位 | 5 >> 1 → 2;-5 >> 1 → -3 |
|
>>> |
无符号右移 | 高位一律补 0,结果恒为非负(视为无符号 32 位整数) | 5 >>> 1 → 2;-1 >>> 1 → 2147483647 |
|
| 赋值运算符 | = |
赋值 | 将右值赋给左变量 | x = y → x = 5 |
+= |
加后赋值 | x = x + y 的简写 |
x += y → x = 12 |
|
-= |
减后赋值 | x = x - y |
x -= y → x = 2 |
|
*= |
乘后赋值 | x = x * y |
x *= y → x = 35 |
|
/= |
除后赋值 | x = x / y |
x /= y → x = 1.4 |
|
%= |
取模后赋值 | x = x % y |
x %= y → x = 2 |
|
<<= |
左移后赋值 | x = x << y |
x <<= 1 → x = 14 |
|
>>= |
算术右移后赋值 | x = x >> y |
x >>= 1 → x = 3 |
|
>>>= |
无符号右移后赋值 | x = x >>> y |
x >>>= 1 → x = 3(若原为正) |
|
&= |
按位与后赋值 | x = x & y |
x &= y → x = 5 |
|
| ` | =` | 按位或后赋值 | `x = x | |
^= |
按位异或后赋值 | x = x ^ y |
x ^= y → x = 2 |
|
| 其他 | _ |
惯用占位符(非运算符) | 在解构赋值中表示丢弃值(TS/JS 允许,但只是普通变量名) | const [_, second] = [1, 2]; |
重要说明(针对 TS/JS):
==vs===:TS 强烈推荐使用===避免隐式类型转换。>>>存在:JS/TS 是少数支持无符号右移的高级语言。++/--是表达式:可出现在赋值右侧(如x = y++),这与 Go 不同。<-不是 TS 运算符:这是 Go 的 channel 操作符,TS 中不存在,建议从表格中移除。_不是运算符:只是社区约定的“丢弃变量”命名,实际仍是合法标识符。
条件语句
条件语句用于基于不同的条件来执行不同的动作。TypeScript 条件语句是通过一条或多条语句的执行结果(True 或 False)来决定执行的代码块。在 TypeScript 中,我们可使用以下条件语句:
if语句:只有当指定条件为true时,使用该语句来执行代码if...else语句:当条件为true时执行代码,当条件为false时执行其他代码if...else if....else语句:使用该语句来选择多个代码块之一来执行switch语句:使用该语句来选择多个代码块之一来执行
if 语句
if 语句由一个布尔表达式后跟一个或多个语句组成。
if(boolean_expression){
// 在布尔表达式 boolean_expression 为 true 执行
}
例如:
const num:number = 5
if (num > 0) {
console.log("数字是正数")
}
if...else 语句
一个 if 语句后可跟一个可选的 else 语句,else 语句在布尔表达式为 false 时执行。
if(boolean_expression){
// 在布尔表达式 boolean_expression 为 true 执行
}else{
// 在布尔表达式 boolean_expression 为 false 执行
}
例如:
const num:number = 12;
if (num % 2==0) {
console.log("偶数");
} else {
console.log("奇数");
}
if...else if....else 语句
if...else if....else 语句在执行多个判断条件的时候很有用。
if(boolean_expression 1) {
// 在布尔表达式 boolean_expression 1 为 true 执行
} else if( boolean_expression 2) {
// 在布尔表达式 boolean_expression 2 为 true 执行
} else if( boolean_expression 3) {
// 在布尔表达式 boolean_expression 3 为 true 执行
} else {
// 布尔表达式的条件都为 false 时执行
}
例如:
const num:number = 2
if(num > 0) {
console.log(num+" 是正数")
} else if(num < 0) {
console.log(num+" 是负数")
} else {
console.log(num+" 不是正数也不是负数")
}
TIPS:
- 一个
if判断语句可以有 0 或 1 个else语句,她必需在else..if语句后面。 - 一个
if判断语句可以有 0 或多个else..if,这些语句必需在else之前。 - 一旦执行了
else..if内的代码,后面的else..if或else将不再执行。
switch 语句
一个 switch 语句允许测试一个变量等于多个值时的情况。每个值称为一个 case,且被测试的变量会对每个 switch case 进行检查。
switch(expression){
case constant-expression :
statement(s);
break; /* 可选的 */
case constant-expression :
statement(s);
break; /* 可选的 */
/* 您可以有任意数量的 case 语句 */
default : /* 可选的 */
statement(s);
}
例如:
const grade:string = "A";
switch(grade) {
case "A": {
console.log("优");
break;
}
case "B": {
console.log("良");
break;
}
case "C": {
console.log("及格");
break;
}
case "D": {
console.log("不及格");
break;
}
default: {
console.log("非法输入");
break;
}
}
TIPS:
switch语句中的expression是一个要被比较的表达式,可以是任何类型,包括基本数据类型(如number、string、boolean)、对象类型(如object、Array、Map)以及自定义类型(如class、interface、enum)等。- 在一个
switch中可以有任意数量的case语句。每个case后跟一个要比较的值和一个冒号。 case的constant-expression必须与switch中的变量expression具有相同或兼容的数据类型。- 当被测试的变量等于
case中的常量时,case后跟的语句将被执行,直到遇到break语句为止。 - 当遇到
break语句时,switch终止,控制流将跳转到switch语句后的下一行。 - 不是每一个
case都需要包含break。如果case语句不包含break,控制流将会 继续 后续的case,直到遇到break为止。 - 一个
switch语句可以有一个可选的default case,出现在switch的结尾。default关键字则表示当表达式的值与所有case值都不匹配时执行的代码块。default case中的break语句不是必需的。
三元/条件运算符
三元运算有 3 个操作数,并且需要判断布尔表达式的值。该运算符的主要是决定哪个值应该赋值给变量。
Test ? expr1 : expr2
Test− 指定的条件语句expr1− 如果条件语句Test返回TRUE则返回该值expr2− 如果条件语句Test返回FALSE则返回该值
循环
有的时候,我们可能需要多次执行同一块代码。一般情况下,语句是按顺序执行的:函数中的第一个语句先执行,接着是第二个语句,依此类推。编程语言提供了更为复杂执行路径的多种控制结构。循环语句允许我们多次执行一个语句或语句组。
for 循环
for ( init; condition; increment ){
statement(s);
}
下面是 for 循环的控制流程解析:
init会首先被执行,且只会执行一次。这一步允许您声明并初始化任何循环控制变量。您也可以不在这里写任何语句,只要有一个分号出现即可。- 接下来,会判断
condition。如果为TRUE,则执行循环主体。如果为FALSE,则不执行循环主体,且控制流会跳转到紧接着for循环的下一条语句。- 在执行完
for循环主体后,控制流会跳回上面的increment语句。该语句允许您更新循环控制变量。该语句可以留空,只要在条件后有一个分号出现即可。- 条件再次被判断。如果为
TRUE,则执行循环,这个过程会不断重复(循环主体,然后增加步值,再然后重新判断条件)。在条件变为FALSE时,for循环终止。
在这里,statement(s) 可以是一个单独的语句,也可以是几个语句组成的代码块。condition可以是任意的表达式,当条件为 TRUE 时执行循环,当条件为 FALSE 时,退出循环。
以下实例计算 5 的阶乘, for 循环生成从 5 到 1 的数字,并计算每次循环数字的乘积。
const num:number = 5;
let i:number;
let factorial = 1;
for(i = num;i>=1;i--) {
factorial *= i;
}
console.log(factorial)
// output: 120
break 语句
break 语句有以下两种用法:
- 当
break语句出现在一个循环内时,循环会立即终止,且程序流将继续执行紧接着循环的下一条语句。 - 它可用于终止
switch语句中的一个case。
如果您使用的是嵌套循环(即一个循环内嵌套另一个循环),break 语句会停止执行最内层的循环,然后开始执行该块之后的下一行代码。
break;
示例:
let i:number = 1
while(i<=10) {
if (i % 5 == 0) {
console.log ("在1~10之间第一个被5整除的数为: "+i)
break // 找到一个后退出循环
}
i++
}
// output: 在1~10之间第一个被5整除的数为: 5
continue 语句
continue 语句有点像 break 语句。但它不是强制终止,continue 会跳过当前循环中的代码,强迫开始下一次循环。
- 对于
for循环,continue语句执行后自增语句仍然会执行。 - 对于
while和do...while循环,continue语句重新执行条件判断语句。
continue;
示例:
let num:number = 0
let count:number = 0;
for(num=0;num<=20;num++) {
if (num % 2==0) {
continue
}
count++
}
console.log ("0~20之间的奇数个数为: "+count)
// output: 0~20之间的奇数个数为: 10
for...in 循环
for...in 语句用于一组值的集合或列表进行迭代输出。
for (let val in list) {
statement(s);
}
// val 需要为 string 或 any 类型。
示例:
let j:any;
const n:any = "a b c"
for(j in n) {
console.log(n[j])
}
// output:
/* a
*
* b
*
* c
*/
for...of 、forEach、every 和 some 循环
此外,TypeScript 还支持 for…of 、forEach、every 和 some 循环。
for...of 语句创建一个循环来迭代可迭代的对象。在 ES6 中引入的 for...of 循环,以替代 for...in 和 forEach() ,并支持新的迭代协议。for...of 允许你遍历 Arrays(数组), Strings(字符串), Maps(映射), Sets(集合)等可迭代的数据结构等。
let someArray = [1, "string", false];
for (let entry of someArray) {
console.log(entry); // 1, "string", false
}
forEach、every 和 some 是 JavaScript 的循环语法,TypeScript 作为 JavaScript 的语法超集,当然默认也是支持的。因为 forEach 在 iteration 中是无法返回的,所以可以使用 every 和 some 来取代 forEach。
let list = [4, 5, 6];
list.forEach((val, idx, array) => {
// val: 当前值
// idx:当前index
// array: Array
});
while 循环
while 语句在给定条件为 TRUE 时,重复执行语句或语句组。循环主体执行之前会先测试条件。
while(condition)
{
statement(s);
}
在这里,statement(s) 可以是一个单独的语句,也可以是几个语句组成的代码块。condition 可以是任意的表达式,当条件为 TRUE 时执行循环。 当条件为 FALSE 时,程序流将退出循环。
实例:
let num:number = 5;
let factorial:number = 1;
while(num >=1) {
factorial = factorial * num;
num--;
}
console.log("5的阶乘为:"+factorial);
// output: 5的阶乘为:120
do...while 循环
不像 for 和 while 循环,它们是在循环头部测试循环条件。do...while 循环是在循环的尾部检查它的条件。
do
{
statement(s);
} while(condition);
请注意,条件表达式出现在循环的尾部,所以循环中的 statement(s) 会在条件被测试之前至少执行一次。
如果条件为 TRUE,控制流会跳转回上面的 do,然后重新执行循环中的 statement(s)。这个过程会不断重复,直到给定条件变为FALSE 为止。
实例:
let n:number = 10;
do {
console.log(n);
n--;
} while(n>=0);
// output:
/* 10
* 9
* 8
* 7
* 6
* 5
* 4
* 3
* 2
* 1
* 0
*/
无限循环
无限循环就是一直在运行不会停止的循环。 for 和 while 循环都可以创建无限循环。
// for 创建无限循环语法格式:
for(;;) {
statement(s);
}
// while 创建无限循环语法格式:
while(true) {
statement(s);
}
函数定义
// 定义
function function_name(param1 [:datatype], param2 [:datatype], ...):return_type {
statements;// 语句
return value;
}
//调用
function_name(param1, param2)
可选参数和默认参数
// 定义
function hello(
firstName: string, // 必须参数
lastName? :string, // 可选参数
hello: string = "Hello", // 默认参数
): string {
let msg: string;
if (lastName) {
return hello +"! " + firstName + " " + lastName;
} else {
return hello +"! " + firstName;
}
}
// 调用 1
const msg = hello("Alice", "Hayes", "Hi")
console.log(msg) // "Hi! Alice Hayes"
// 调用 2
const msg = hello("Ben")
console.log(msg) // "Hello! Ben"
TIPS:
?代表这个参数是可选的。例如lastName? :string。- 可以在定义函数时,为参数指定默认值。例如
hello: string = "Hello"。
剩余参数
有一种情况,我们不知道要向函数传入多少个参数,这时候我们就可以使用剩余参数来定义。剩余参数语法允许我们将一个不确定数量的参数作为一个数组传入。
匿名函数
匿名函数是一个没有函数名的函数。匿名函数在程序运行时动态声明,除了没有函数名外,其他的与标准函数一样。我们可以将匿名函数赋值给一个变量,这种表达式就成为函数表达式。语法格式如下:
var res = function( [arguments] ) { ... }
不带参数匿名函数:
const msg = function() {
return "hello world";
}
console.log(msg())
// output: hello world
带参数匿名函数:
const res = function(a:number,b:number) {
return a*b;
};
console.log(res(12,2))
// output: 24
匿名函数自调用
匿名函数自调用在函数后使用 ( ) 即可:
(function () {
var x = "Hello!!";
console.log(x)
})()
// output: Hello!!
构造函数
TypeScript 也支持使用 JavaScript 内置的构造函数 Function() 来定义函数,语法格式如下:
var res = new Function ([arg1[, arg2[, ...argN]],] functionBody)
参数说明:
arg1,arg2, …argN:参数列表。functionBody:一个含有包括函数定义的 JavaScript 语句的字符串。
例如:
const myFunction = new Function("a", "b", "return a * b");
const x = myFunction(4, 3);
console.log(x);
// output: 12
递归函数
递归函数即在函数内调用函数本身。
举个例子:从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?“从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?‘从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?……’"🤪🤪🤪
function factorial(num: number): number {
// 停止执行
if (num <= 0) {
return 1;
} else {
// 调用自身,开始递归
return (num * factorial(num- 1));
}
};
// 输出 720
console.log(factorial(6));
Lambda 函数
Lambda 函数也称之为箭头函数。箭头函数表达式的语法比函数表达式更短。函数只有一行语句:
([param1, param2,…paramN]) => statement;
// 等价于:
function funcName([param1, param2,…paramN]) {
return statement;
}
例如:
const foo = (x:number) => 10 + x;
// output: 110
console.log(foo(100))
我们可以不指定函数的参数类型,通过函数内来推断参数类型。
const func = (x)=> {
if(typeof x=="number") {
console.log(x+" 是一个数字")
} else if(typeof x=="string") {
console.log(x+" 是一个字符串")
}
}
// output: 12 是一个数字
func(12)
// output: Tom 是一个字符串
func("Tom")
函数重载
重载是方法名字相同,而参数不同,返回类型可以相同也可以不同。每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。
// 1. 重载签名(可写多个)
function disp(s1:string):void;
function disp(n1:number,s1:string):void;
// 2. 实现签名(必须兼容所有重载)
function disp(x:any,y?:any):void {
console.log(x);
console.log(y);
}
// 3. 调用
disp("abc")
disp(1,"xyz");
/* output:
* abc
* undefined
* 1
* xyz
*/
TIPS:
- 重载签名只能写“形参 + 返回值”类型,不能有函数体。
- 最后必须提供一个 实现签名(implementation),它用
function/=>/function表达式都可以。 - 实现签名的参数类型必须是所有重载类型的 联合(或更宽),否则会报错。
类(Class)
以下有三种常用的 class 定义方式:
◾方法一:最常用
// 定义
type User = {
id: number;
name: string;
vip?: boolean; // 可选属性
readonly createdAt: Date; // 只读属性
};
// 使用
const u: User = { id: 1, name: 'Tom', createdAt: new Date() };
这种方式最直观、最轻量,90 % 的场景够用。但无法给属性加“默认值”或“实现”——它只是“类型”。
◾方法二:需要“继承”或“类型合并”
interface User {
id: number;
name: string;
}
// 可扩展
interface User {
vip?: boolean; // 同名 interface 会自动合并
}
// 可继承
interface VipUser extends User {
level: number;
}
方法二支持“同名合并”和“继承”,在写库、框架或需要多次扩展时很方便。但比 type 稍啰嗦,且不能表达“联合类型”等复杂类型。
◾方法三:直接用 class
class User {
id: number;
name: string;
vip = false; // 带默认值
constructor(id: number, name: string) {
this.id = id;
this.name = name;
}
greet() { // 还能带方法
console.log(`Hi, ${this.name}`);
}
}
方法三中“类型 + 实现”一次搞定,还能放方法;编译后真有 JS 类。缺点是会生成运行时代码,如果只是纯数据结构就“太重”。
在函数定义时直接指定 class 类型
// The parameter's type annotation is an object type
function printCoord(pt: { x: number; y: number }) {
console.log("The coordinate's x value is " + pt.x);
console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 3, y: 7 });
这里相当于方法三,只不过把代码嵌入到函数定义的过程中了。
类型别名 Type Aliases
我们一直通过直接在类型注解中编写对象类型和联合类型来使用它们。这很方便,但通常我们希望多次使用相同的类型,并使用一个名称来引用它。类型别名就是其字面意思——任何类型的名称。类型别名的语法如下:
type Point = {
x: number;
y: number;
};
// Exactly the same as the earlier example
function printCoord(pt: Point) {
console.log("The coordinate's x value is " + pt.x);
console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 100, y: 100 });
接口声明 Interfaces
接口声明是另一种命名对象类型的方式
interface Point {
x: number;
y: number;
}
function printCoord(pt: Point) {
console.log("The coordinate's x value is " + pt.x);
console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 100, y: 100 });
语法很像类型别名,在很多情况下你可以根据自己的喜好来选择使用它们。几乎 interface 的所有特性在 type 中都可用 关键的区别在于类型不能重新打开以添加新属性,而接口总是可以扩展的。
// Extending an interface
// 扩展接口
interface Animal {
name: string;
}
interface Bear extends Animal {
honey: boolean;
}
const bear = getBear();
bear.name;
bear.honey;
// Adding new fields to an existing interface
// 向现有接口添加新字段
interface Window {
title: string;
}
interface Window {
ts: TypeScriptAPI;
}
const src = 'const a = "Hello World"';
window.ts.transpileModule(src, {});
参考文档
- [1] 日常类型(Everyday Types): https://www.typescriptlang.org/docs/handbook/2/everyday-types.html
- [2] 类型缩小(Narrowing): https://www.typescriptlang.org/docs/handbook/2/narrowing.html
- [3] 枚举类型(Enums):https://www.typescriptlang.org/docs/handbook/enums.html