类型推论
什么是类型推论
以下代码虽然没有指定类型,但是会在编译的时候报错:
let myFavoriteNumber = 'seven';//虽然没有给数据类型,但可以通过赋的值推论出来
myFavoriteNumber = 7; // error 报错,必须是字符串类型
事实上,它等价于:
let myFavoriteNumber: string = 'seven';
myFavoriteNumber = 7;
TypeScript 会在没有指定类型的时候推测出一个类型,这就是类型推论。
如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查:
let myFavoriteNumber;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
联合类型
联合类型(Union Types)表示取值可以为多种类型中的一种.
let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';//可以是字符串
myFavoriteNumber = 7;//可以是number
联合类型使用 |
分隔每个类型。
访问联合类型的属性和方法
当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法:
function getLength(something: string | number): number {
return something.length;
}
// error TS2339: Property 'length' does not exist on type 'string | number'. Property 'length' does not exist on type 'number'.
上例中,length
不是 string
和 number
的共有属性,所以编译器报错。
访问 string
和 number
的共有属性是没问题的:
function getString(something: string | number): string {
return something.toString();
}
联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型:
let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
console.log(myFavoriteNumber.length);
myFavoriteNumber = 7;
console.log(myFavoriteNumber.length); // error TS2339: Property 'length' does not exist on type 'number'.
在上例中,第 2 行 myFavoriteNumber
被推断成 string
类型,因此访问其 length
属性不会报错。而第 4 行被推断成 number
,访问 length
就报错了。
类型断言
断言就是假设的意思
类型断言(Type Assertion)可以用来手动指定一个值的类型。
语法
<type> value //格式
//示例
function getLength(something: string | number): number {
return (<string>something).length;
}//在react里慎用,于jsx语法冲突,会当成非法组件
// or
value as type //格式
//示例
function getLength(something: string | number): number {
return (something as string).length;
}
在 tsx
中必须使用后面一种。
前面在联合类型中我们提到过,当 Typescript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法:
function getLength(something: string | number): number {
return something.length;
}
// error TS2339: Property 'length' does not exist on type 'string | number'. Property 'length' does not exist on type 'number'.
在这里,我们希望访问 length 属性:
function getLength(something: string | number): number {
if (something.length) {
return something.length;
} else {
return something.toString().length;
}
}
// error TS2339: Property 'length' does not exist on type 'string | number'. Property 'length' does not exist on type 'number'.
在上例中,访问 something.length
的时候会报错,因为 length
并不是公共属性。此时,我们就可以使用类型断言,将 something
断言成 string
:
function getLength(something: string | number): number {
if ((<string>something).length) {
return (something as string).length;
} else {
return something.toString().length;
}
}
类型断言不是类型转换,断言成一个联合类型中不存在的类型是不允许的:
function toBoolean(something: string | number): boolean {
return <boolean>something;
}
// error TS2352: Conversion of type 'string | number' to type 'boolean' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. Type 'number' is not comparable to type 'boolean'.
类型别名
类型别名用来给一个类型起个新名字,常用于联合类型。
type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
function getName(n: NameOrResolver): Name {
if (typeof n === 'string') {
return n;
} else {
return n();
}
}
字符串字面量类型
字符串字面量类型用来约束取值只能是某几个字符串中的一个。
type EventNames = 'click' | 'scroll' | 'mousemove';
function handleEvent(ele: Element | null , event: EventNames) {
// do something
}
handleEvent(document.querySelector('hello'), 'scroll');
handleEvent(document.querySelector('world'), 'dbclick'); // error 报错,只能取EventNames 里面的字符串
上例中,我们使用 type
定了一个字符串字面量类型 EventNames
,它只能取三种字符串中的一种。
类型别名与字符串字面量类型都是使用 type 进行定义。