类型
js类型
JavaScript 的类型分为两种:原始数据类型(Primitive data types)和对象类型(Object types)。
原始数据类型包括:布尔值、数值、字符串、null
、undefined
以及 ES6 中的新类型 Symbol
。
在JavaScript中undefined,是全局作用于的一个属性,他会赋值给哪些声明但未初始化的变量;
null是一个字面量(不是全局对象的一个属性),他可以赋值给哪些没有值得变量;
ts类型
在TypeScript中我们可以使用undefined和null来定义两个原始类型数据:
let test: null = null;
console.log(test); //null
let test1: undefined = undefined;
console.log(test1); //undefined
undefined
和 null
是所有类型的子类型。也就是说 undefined
类型的变量,可以赋值给 所有类型的变量 如:
let u1: undefined;
let num1: number = u1;
console.log(num1); //undefined
而 void
类型的变量不能赋值给 number
类型的变量:
let u: void;
let num: number = u; //Type 'void' is not assignable to type 'number'.
数组类型
在 TypeScript 中,数组类型有多种定义方式,比较灵活。
最简单的方法是使用「类型 + 方括号」来表示数组:
数组的项中不允许出现其他类型;
//正确
let numArray: number[] = [1,2,3];
let strArray: string[] = ['1','2','3'];
//Type 'string' is not assignable to type 'number'.
let numArray: number[] = ['1',2,3];
也可以使用数组泛型(Array Generic) Array<elemType>
来表示数组:
let objArray: Array<object> = [{a:1},{b:2}];
任意值any
任意值(Any)用来表示允许赋值为任意类型。
any的定义
如果是普通类型,在赋值过程中是不能改变类型的 如:
let myTest: string = 'test';
myTest = true;
//Type 'true' is not assignable to type 'string'.
如果是any,允许被赋值为任意类型
let myTest: any = 'test';
myTest = true;
console.log(myTest); //true
any的属性
在任意值上访问任何属性都是允许的:
let anyThing: any = 'hello';
console.log(anyThing.myName)
在声明变量声明是未指定类型,那么就会被识别成任意类型
类型推论
如果没有明确的指定类型,那么 TypeScript 会依照类型推论(Type Inference)的规则推断出一个类型。如下:
let myType = 'one';
myType = 1;//Type '1' is not assignable to type 'string'.
等价于
let myType:string = 'one';
myType = 1;//Type '1' is not assignable to type 'string'.
TypeScript 会在没有明确的指定类型的时候推测出一个类型,这就是类型推论。
如果定义时没有赋值,不管之后有没有赋值,都会被推断成any类型
联合类型
TypeScript允许声明联合类型。联合类型类声明那些可以存储多种类型的变量
let myType: string | number;
myType = 'one'; //one
myType = 1;//1
myType = true;//Type 'true' is not assignable to type 'ReactText'.
联合类型使用 |
分隔每个类型。
接口
接口基础用法
在面向对象语言中,接口(Interfaces)是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类(classes)去实现(implement)。
TypeScript 中的接口是一个非常灵活的概念,除了可用于[对类的一部分行为进行抽象]()以外,也常用于对「对象的形状(Shape)」进行描述。
定义一个变量myJson,类型时Person
interface Person {
name:string;
age: number;
}
//定义变量比接口少一些属性
//Property 'age' is missing in type '{ name: string; }' but required in type 'Person'.
let myJson: Person = {
name: 'jerry'
}
//定义的变量属性比接口多
//Type '{ name: string; age: number; other: string; }' is not assignable to type 'Person'.
Object literal may only specify known properties, and 'other' does not exist in type 'Person'.
let myJson: Person = {
name: 'jerry',
age: 1,
other: 'test'
}
可选属性
接口里面的属性不全都是必需的,有些只是在某些条件下存在或者根本就不存在。
可选属性在应用”option bags“模式时很常用,即给函数传入的对象中只有部分属性赋值了
interface Person {
name:string;
age?: number;
}
//正常运行
let myJson: Person = {
name: 'jerry'
}
可选属性的含义是该属性可以不存在。
这时仍然不允许添加未定义的属性。
任意属性
interface Person {
name:string;
age: number;
[params: string]: any
}
let myJson: Person = {
name: 'jerry',
age: 1,
order: {
test: 'test'
}
}
用[params: string]定义了属性取string类型的值;
注意:一旦定义了任意属性,那么之前定义的确定属性和可选属性都必须是他的子集;
//Property 'name' of type 'string' is not assignable to string index type 'object'.
//Property 'age' of type 'number' is not assignable to string index type 'object'.
interface Person {
name:string;
age: number;
[params: string]: object
}
let myJson: Person = {
name: 'jerry',
age: 1,
order: {
test: 'test'
}
}
只读属性
有时候我们希望对象中的一些字段只能在创建的时候被赋值,那么可以用 readonly
定义只读属性:
interface Person {
readonly id: number;
name:string;
age: number;
[params: string]: any
}
let myJson: Person = {
id: 123,
name: 'jerry',
age: 1,
order: {
test: 'test'
}
}
//Cannot assign to 'id' because it is a read-only property.
myJson.id = 345;
readonly和const
最简单判断该用readonly
还是const
的方法是看要把它做为变量使用还是做为一个属性。 做为变量使用的话用const
,若做为属性则使用readonly
。
函数类型
在 JavaScript 中,有两种常见的定义函数的方式——函数声明(Function Declaration)和函数表达式(Function Expression)
用接口定义函数的形状
使用接口的方式来定义一个函数需要符合的形状:
interface SearchFunc {
(source: string, subStr: string): boolean;
}
let mySearch: SearchFunc = (source:string, subStr:string) => {
return source.search(subStr) !== -1;
}
有可选参数的函数
与JavaScript不同,调用函数时传的参数的数量或者类型不符合函数中定义的参数要求是,TypeScript编译器会报错;如:
add = (foo:number,bar:number,foobar:number):number => {
return foo+bar+foobar;
}
add(); //提供的参数不匹配函数的签名
add(1,2);//提供的参数不匹配函数的签名
add(1,2,3); 返回6
在一些场景下我们不需要传所有的参数;TypeScript一个函数可选参数的特性;
在TypeScript中通过在函数参数后面追加一个?,指定参数是可选的
add = (foo:number,bar:number,foobar?:number):number => {
return foo+bar+foobar;
}
add(); //提供的参数不匹配函数的签名
add(1,2);返回3
add(1,2,3); 返回6
有默认参数的函数
当函数有可选参数时,我们必须检测参数是否被传递了 如:
add = (foo:number,bar:number,foobar?:number):number => {
return foo+bar+(foobar !== undefined ? foobar : 1 );
}
这样来做并没有错,但是可以通过提供foobar的参数的默认值,来替代标记其为可选参数,以改善可读性
add = (foo:number,bar:number,foobar:number=1):number => {
return foo+bar+foobar;
}
在声明函数签名时使用=提供一个默认值,即可指定函数参数是可选的;TypeScript编译会在JavaScript输出结果中生成一个if结构,在foobar参数没有传递函数时设置一个默认值;
function add(foo, bar, foobar){
if(foobar === void 0){
foobar = 1;
}
return foo+bar+foobar;
}
void 0是TypeScript编译器检测一个变量是否为undefined的用法;
有剩余参数的函数
add = (foo:number,bar:number,foobar:number=1):number => {
return foo+bar+foobar;
}
如果想调用add传递更多个参数该如何解决呢?
使用剩余参数,剩余参数语法允许把不限量的参数表示为一个数组
add = (...foo:number[]):number => {
let res = 0;
for(let i=0; i < foo.length; i++){
res += foo[i];
}
return res;
}
用...foo替换了参数foo、bar、foobar;一个剩余参数必须包含一个数组类型,否则会出现编译错误;
add(); //return 0
add(1); //return 1
add(1,2,3,4,5); //return 15