TypeScript Basics & Basic Types
Using Types
一个简单的 JS 函数
const add = (a, b) => a + b;正常情况下,他返回两个数字的和,但如果有一个数字以字符串形式输入,返回的结果则会是字符串的拼接
console.log(add(5, 2.8)); // 7.8
console.log(add("5", 2.8)); // 52.8使用 TS 在编写时就发现这个问题,而不是在编译的时候才发现问题。通过在参数后加’:',再加上其限定类型即可。
const add = (a: number, b: number) => a + b;
console.log(add("5", 2.8)); // errorTypeScript Types vs JavaScript Types
JavaScript 中也有 typeof 操作符来检查参数的类型,就像这样
const add = (a: number, b: number) =>
typeof a !== "number" || typeof b !== "number"
? throw new Error("Incorrect input!")
: a + b;这样同样可以做类型检查,但是这样很复杂,同时,依然无法在 Coding 的时候发现问题,只有当编译错误的时候,才会发现参数的类型错误,使用 TypeScript 规避这样的麻烦和错误,同时 TypeScript 拥有的类型也远远超过 JavaScript。
Working with Numbers, Strings & Booleans
现在来进一步扩充我们的 add 函数,添加一个参数 showResult,类型为 boolean,来决定函数执行完后是答应结果还是返回结果。再增加一个 phrase 参数,类型为 string,如果要直接打印结果,前面想添加的输出内容作为 phrase 参数。
const add = (n1: number, n2: number, showResult: boolean, phrase: string) =>
showResult ? console.log(phrase + n1 + n2) : n1 + n2;
const number1 = 5; // 5.0
const number2 = 2.8;
const printResult = true;
const resultPhrase = "Result is: ";
add(number1, number2, printResult, resultPhrase);Type Assignment & Type Inference
TypeScript 代码会经过 Compiler 编译后变为绝大多数浏览器都可以理解的 JavaScript 代码。而且里面不带有类型推断,因为 JS 并没有这个能力。
TS 会对变量进行类型推断。
例如
const number = 5;如果鼠标放在 number 上,会看到显示 ‘const nimber: 5’,这是因为 number 这个时候是个常量,他会把它看作就是 5.如果使用 let 声明呢?
let number: number;
number = 5;
let n = 5;鼠标放在 number 和 n 上,就会显示 ‘let number: number’、‘let n:number’,因为我们声明 number 是一个 number 类型,同时 TypeScript 会推断 n 也是 number 类型。
n = "5";
number = "5";这种行为会报错,因为我们已经声明这两个变量是 number 类型,不可以被赋值为 string 类型。
Object Types
对于 Object 如何处理?
const person = {
name: "jack",
age: 30,
};这是一个 object,可以使用点操作符访问内部键值对。鼠标放在 person 上,会出现它的类型。
const person: {
name: string;
age: number;
};这看起来也像一个 object,但是不是,**每个键值对的分割使用的是’;‘而不是’,',**而这就是 person 在 TS 里的类型。
如何确定类型呢
const person: object = {
//...
};如果这样子赋类型,我们是无法使用点操作符访问内部对象的,typesript 会认为这只是一个最简单的 object 类型,就是 JavaScript 里的与 number、boolean 齐名的 object 类型。
const person: {
name: string;
age: number;
} = {
name: "jack",
age: 30,
};采用这种方式,对 object 里面每一个键的值声明清楚其类型即可。
Array Types
数组作为 JavaScript 里就存在的引用类型,也可以在 TypeScript 中做限制。
const person = {
name: "jack",
age: 30,
hobbies: ["Sports", "Cooking"],
};这个时候去看 hobbies 的类型。显示的是 (property) hobbies: string[]。这表明他是一个有 string 组成的 Array。
若要声明一个有 string 组成的 Array,可以这样
let favouriteActivites: string[];
favouriteActivites = ["Sports"];我们可以遍历这个数组看看
for (const hobby of person.hobbies) {
console.log(hobby.toUpperCase());
console.log(hobby.map()); //---> error: TS knows that the string type doesn't have the method 'map'
}但是这样会报错,在遍历的时候,TypeScript 知道 hobbies 数组里面的值类型为 hobby,所以当我们在 hobby 下调用点操作符时,会为我们显示属于 string 的方法。但是 map 方法不会,他知道 string 类型是不会有 map 方法的
Working with Tuple
Tuple 是 TypeScript 提供的一种类型,他像是一个数组,但是它的长度,每一个位置的值的类型都是固定的。
const person: {
// ....
role: [number, string];
} = {
//....
role: [2, "author"],
};现在已经声明好了 role 作为一个 tuple,他长度只能是 2,第一个必须是 number 且第二个一定是 string。如下的代码会报错,因为类型不符合。同样的,超出长度的赋值也是会报错的。
person.role[1] = 10;
person.role = [0, "admin", "user"];但是很可惜,对于 push 这样的操作,TypeScript 无法检测推入的长度是否会超出,以及推入的这一位,是否是这一位应该为的类型。(即通过 push 在第二个位置推入一个 number)。
person.role.push("admin");Working with Enums
TypeScript 提供了枚举 Enum 类型。
在 JavaScript 中会遇到一些问题,给一些东西赋固定值的时候,会输入错具体的值,使得程序无法正常运行,如下:
const person = {
role: "READ ONLY",
};
if (person.role === "READ-ONLY") console.log("Read only.");一个字符之差,导致这条信息永远不被输出,所以我们有其他的解决方案
const ADMIN = "ADMIN";
const READ_ONLY = "READ_ONLY";
const person = {
role: READ_ONLY,
};
if (person.role === READ_ONLY) console.log("Read only.");这可以规避上述的错误,但依然略显繁琐,可以使用 TypeScript 的 enmu 类型。
enum Role {
ADMIN,
READ_ONLY,
AUTHOR,
}
const person = {
// ...
role: Role.ADMIN,
};
if (person.role === Role.ADMIN) console.log("I am Admin");这样又方便而且不会出错,类型分明。同时,如果把鼠标移到 Role 里每个项的上,可以看到他们的具体值。被分别按顺序赋予了 1、2、3。
如果想要改变他们的初始值也可以,例如
enum Role {
ADMIN = 200,
READ_ONLY,
AUTHOR,
}这样 ADMIN 的值会是 200,剩余两个也是以此增加,分别为 201 和 202。
当然也可以赋予其他的类型。
enum Role {
ADMIN = "ADMIN",
READ_ONLY = 100,
AUTHOR = "AUTHOR",
}这同样可行。
The any Type
any 告诉 TypeScript 这个值的类型可以为任何,例如
const a = any[];这个数组里面的值可以是任何类型,没有限制。
尽量避免使用 any,TypeScript 没有办法对他做任何检查,any 用的多和写 JavaScript 没有区别
Union Types
有时候我们希望我们的函数有更多的功能,接收的参数类型不同,返回的结果也不同,这个时候可以使用 Union Type
const combine = (a: number | string, b: number | string) =>
typeof a === "number" && typeof b === "number"
? a + b
: a.toString() + b.toString;
const combineAges = combine(30, 26);
console.log(combineAges);
const combineNames = combine("Du", "Lang");
console.log(combineNames);在这个例子中,combine 函数的参数接收两种类型的参数,string 和 number,如果两个参数都为 number 类型,那就对他们做简单的相加,否则就做及简单的字符串拼接。
使用 Union type 我们限制了参数的类型的同时,扩充函数的功能
Literal Types
Literal type 为写死的内容。例如之前的
const number = 5;查看它的类型会发现它就只写了一个 5,我们可以利用这个特性。
const combine = (
a: number | string,
b: number | string,
resultConversion: "as-number" | "as-text"
) =>
(typeof a === "number" && typeof b === "number") ||
resultConversion === "as-number"
? +a + +b
: a.toString() + b.toString;
const combineAges = combine(30, 26, "as-number");
console.log(combineAges);
const combineNames = combine("Du", "Lang", "as-text");
console.log(combineNames);这个时候,第三个参数 resultConvension 的值就只能为二者其一,被严格限定,避免出现错误。
如果传的参数或者在函数内判断其的值不为这二者其一,TypeScript 都会报错,从而规避错误。
Type Aliases Custom Types
类型别名,使用 type 操作符定义。
type Combinable = number | string;
type ConversionDescriptor = "as-number" | "as-text";
const combine = (
a: Combinable,
b: Combinable,
resultConversion: ConversionDescriptor
) =>
(typeof a === "number" && typeof b === "number") ||
resultConversion === "as-number"
? +a + +b
: a.toString() + b.toString;如果我们的参数类型复杂,这样会更清晰,同时也更能明确为什么是这些类型。也可以编码更加复杂的类型定义。并且有着良好的复用性。
Function Return Types && void
我们可以声明 function 的返回类型。先来看看
const add = (a: number, b: number) => a + b;鼠标放大 add 上 会显示 const add: (a: number, b: number) => number,箭头后面的 number 表面它会返回一个 number 类型的值,这是由 TypeScript 自己推断出来的。我们也可以显式的声明
const add = (a: number, b: number): number => a + b;也是通过 ‘:’ 来做声明,如果你不知道返回类型究竟是什么,让 TypeScript 自己推断就好。
对于不返回东西的 function,也提供了 void 类型,就和其它语言一样。
const printResult = (n: number): void => console.log("Result: " + n);这里即使不写清楚 void,TypeScript 也会自己推断出这是 void 类型。
还有另一种返回类型,undefined,他会写 return 语句但是不不返回任何东西
function returnUndefined(): undefined {
return;
}Functions as Types
我们有时候也会希望函数本身可以作为一种类型,或者特定的一种函数,作为一种类型。
const add = (a: number, b: number): number => a + b;
let combineFunction;
combineFunction = add;combineFunction 的类型是 type 是 any,所以可以赋值为 add。
我们也可以限定其类型为 Function。
let combineFunction: Funtcion;但这样太宽泛了,它可以被赋值为任意一个函数都可以。可以进一步限制。
const add = (a: number, b: number): number => a + b;
const printResult = (n: number): void => console.log("Result: " + n);
let combineFunction: (a: number, b: number) => number;
combineFunction = add;
// combineFunction = printResult;这个时候,combineFunction 就只可以被赋值为 add 了,因为他接受两个参数,类型为 number,且返回一个 number 值。
Functions Types & Callback
有时候需要传入回调函数,我们也可以对回调函数,作出一定的限制
const add = (a: number, b: number, callback: (n: number) => number): number =>
callback(a + b);
add(1, 2, (num) => num * 10);这样我们就限定了,回到函数的类型,参数类型,和返回类型。
Unknown Type
如果不知道你要储存的变量的类型,但你知道你最终要用他做什么,使用 unknown 类型
let userInput: unknown;
let userName: string;
userInput = 5;
userInput = "Max";
if (typeof userInput === "string") userName = userInput;可以看到,unknown 类型可以被赋值为任何值,类似 unknown。但不能随意给其他变量赋值,可以在判断类型后赋值,否则会报错。
同样,尽量不要用 unknown 类型,如果知道有哪些类型,union 是更好的选择。
Never Type
还有一种返回类型,never。他表示从不返回任何值,例如抛出异常或者其他的等等。
function generateError(msg: string, code: number): never {
throw { msg, code };
}
generateError("An error", 500);
















