TypeScript(一)基础类型
1. 布尔值
使用 boolean 定义布尔值类型:
let done: boolean = true
注意:使用构造函数创建的值不是boolean类型,而是Boolean对象
let bool: boolean = new Boolean(true)
// Type 'Boolean' is not assignable to type 'boolean'.
// 'boolean' is a primitive, but 'Boolean' is a wrapper object. Prefer using 'boolean' when possible.
直接调用Boolean创建的值是boolean类型
let bool: boolean = Boolean(false)
console.log(bool) // false
2. 数值类型
类似于javascript ,typescript支持十进制、十六进制、二进制、八进制字面量。
// 十进制
let num: number = 123
// 十六进制
let x: number = 0xf00d
console.log(x)
// 二进制
let y: number = 0b1010
console.log(y)
// 八进制
let z: number = 0o744
console.log(z)
编译结果:
var num = 123;
var x = 0xf00d;
console.log(x);
// 二进制
var y = 10;
console.log(y);
// 八进制
var z = 484;
console.log(z);
3. 字符串
和javascript一样,可以使用双引号("")、单引号('')、反引号(``)表示字符串
let str: string = 'sina'
// 还可使用模板字符串
let fullname: string = 'mike'
let age: number = 12
let info = `the person info:
name is ${fullname};
age is ${age}`
console.log(info)
编译结果:
var fullname = 'mike';
var age = 12;
var info = "the person info:\n name is " + fullname + ";\n age is " + age;
console.log(info);
4. 数组
TypeScript中有两种方式表示数组,比较灵活:
- 在元素类型后面接上
[]
,表示由此类型元素组成的一个数组
// 元素为数字类型的数组
let arr: number[] = [2, 3, 4]
编译结果:
var arr = [2, 3, 4];
- 数组中不允许出现指定类型之外的其他类型:
let nums: number[] = [1, '1', 2, 3, 5]
// Type 'string' is not assignable to type 'number'
- 数组个别方法的参数也会根据数组在定义时约定的类型进行限制:
let nums: number[] = [1, 1, 2, 3, 5];
nums.push('8');
// Argument of type '"8"' is not assignable to parameter of type 'number'.
- 第二种方式是使用数组泛型,Array<元素类型>
// 元素为字符串的数组
let array: Array<string>;
array = ['sina', 'mike']
console.log(array)
编译结果:
var array;
array = ['sina', 'mike'];
console.log(array);
- 如果数组元素既可以是number又可以是string类型,可以通过以下方式:
let arr: (string | number)[] = [1, 4, 'sina']
console.log(arr)
注意:指示类型的圆括号()不可以省略,如果省略则会被编译器认为数组元素是其中一种类型
let arr: string | number[] = [3, 4, 5]
console.log(arr)
// let arr: string | number[] = [3, 4, 5, 'sina'] // 报错
- 还可以使用数组泛型表示元素为多种类型的数组
let arr: Array<string | number> = [3, 4, 'sina']
console.log(arr)
5. 元组 Tuple
元组可以理解成数组的扩展,表示一个已知长度和类型的数组,各元素的类型不必相同
- 定义一个第一项和第三项为string类型,第二项为数值长度为3的数组
let tuple: [string, number, string] = ['sina', 3, 'mike']
- 直接对元组类型的变量进行初始化或者赋值的时候,需要提供所有元组类型中指定的项
tuple = ['hello', 33, 'jack']
- 访问已知索引的元素:
let tuple: [string, number, string] = ['sina', 3, 'mike']
tuple[2].substr(2) // 'ke'
tuple[1].toFixed(2) // '3.00'
- 修改某一项的值:
let tuple: [string, number, string] = ['sina', 3, 'mike']
tuple[1] = 22
- 超出数组长度的元素称为越界元素:
const arr: [string, number] = ['sian', 4]
arr[2] = 2
// Tuple type '[string, number]' of length '2' has no element at index '2'.
- 通过数组方法修改或者添加元素时,所添加的元素必须是限制类型之一:
let arr: [string, number] = ['hello', 12]
arr.splice(1, 1, 'sina') // ['hello', 'sina']
arr.push(5) // ['hello', 12, 5]
arr.psuh(true) // 报错:Argument of type 'true' is not assignable to parameter of type 'string | number'.
6. 枚举 Enum
枚举类型用于取值被限定在一定范围内的场景。比如某个值的状态由数字表示,每个数字对应一种状态,但是我们得记忆或认知是对语义化的东西敏感,记不住那些数字,于是可以通过枚举表示。
枚举使用 enum
关键字定义:
enum Status {
pending,
resolve,
reject
}
枚举成员的序列号默认被赋值为从 0 开始递增的数字,同时也会对枚举值到枚举名进行反向映射:
console.log(Status.resolve) // 1
console.log(Status[2]) // 'reject'
编译结果:
var Status;
(function(Status) {
Status[Status["pending"] = 0] = "pending";
Status[Status["resolve"] = 1] = "resolve";
Status[Status["reject"] = 2] = "reject";
})(Status || (Status = {}));
自定义赋值
- 可以给枚举项手动赋值,未手动赋值的枚举项会接着上一个枚举项递增。
enum Days {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat};
console.log(Days.Sun) // 7
console.log(Days.Mon) // 1
console.log(Days.Tue) // 2
console.log(Days.Sat) // 6
如果未手动赋值的枚举项与手动赋值的重复了,TypeScript 并不会察觉到这一点的:
enum Colors { green = 3, red = 1, blue, orange, pink, white }
console.log(Days.orange) // 3
console.log(Days.green) // 3
console.log(Days[3]) // 'orange'
console.log(Days[3]) // 'orange'
以上枚举项递增到orange时重复了,但是TypeScript并没有报错,导致 Colors[3]
的值开始是 green
,之后被 orange
重写了。
编译结果:
var Colors;
(function(Colors) {
Colors[Colors["green"] = 3] = "green";
Colors[Colors["red"] = 1] = "red";
Colors[Colors["blue"] = 2] = "blue";
Colors[Colors["orange"] = 3] = "orange";
Colors[Colors["pink"] = 4] = "pink";
Colors[Colors["white"] = 5] = "white";
})(Colors || (Colors = {}));
所以使用的时候一定注意,不要出现覆盖的情况。
- 手动赋值的枚举项也可以为小数或负数,此时后续未手动赋值的项的递增步长仍为 1:
enum Colors { green = 3, red = 1.5, blue, orange, pink, white }
console.log(Days.orange) // 3
console.log(Days.green) // 3.5
console.log(Days[3.5]) // 'orange'
console.log(Days[3.5]) // 'orange'
7. 任意值 Any
Any用来表示允许赋值为任意类型。开发中有些值在编码阶段并不清楚是什么类型,只有在运行时才知道是什么类型(比如来自用户输入)或第三方代码库。
任意值类型
- 一个普通类型的值,在赋值过程中是不允许改变类型的:
let str: string = 'sina'
str = 7
// Type '7' is not assignable to type 'string'.
- 如果是 any 类型,则允许被赋值为任意类型:
let foo: any = 'sina'
foo = 12
foo = true
console.log(foo)
- 如果用const声明必须有初始值,和js是一致的:
const bar: any = 'sina'
console.log(bar)
- 声明一个元素为任意类型的数组:
const arrAny: any[] = [3, 'sian', true, [3]]
console.log(arrAny)
- 长度仍然不可越界:
const arrAny1: [string, any] = ['sina', 4]
console.log(arrAny1)
任意值的属性和方法
- 任意值上允许访问任何属性:
let str: any = 'hello'
console.log(str.foo) // undefined
// 编译器并不会报错,转成js后运行报错:Cannot read property 'bar' of undefined
console.log(str.foo.bar)
- 也允许调用任何方法
let str: any = 'sina'
str.getName()
未声明类型的变量
变量如果在声明时未指定类型,则会被识别为任意值类型
let str
str = 'sina'
str = 7
str.foo('Tom')
等价于:
let str: any
str = 'sina'
str = 7
str.foo()
8. Void
javasctipt中如果函数没有返回值,默认返回undefined。
void表示没有任何类型,在TypeScript用void表示一个没有返回值的函数。
function foo(): void {
console.log('hello void')
}
函数执行后仍然返回 undefined
。
为什么指定void类型,返回仍然是undefined?
因为默认情况下null和undefined是所有类型的子类型(包括void)。也就是说可以把null和undefined赋值给number等其他类型的变量。(前提是 strictNullChecks
为关闭状态)。
事实上声明一个 void 类型的变量没有什么用,因为只能将它赋值为 undefined 或 null( strictNullChecks
是关闭状态)
let unusable: void = undefined
unusable = null
// 如果strictNullChecks为开启状态下则会报错: Type 'null' is not assignable to type 'void'.
如果函数参数未指定类型,则隐式具有“any”类型。
const baz = (text): void => {
console.log(text)
}
// Parameter 'text' implicitly has an 'any' type.
9. Null & Undefined
let u: undefined = undefined
let n: null = null
默认情况下,null 和 undefined是所有类型的子集(包括void),可以把他们赋值给这些类型的变量。
但是如果开启了 strictNullChecks
标记,null和undefined只能赋值给void和它们自己。
10. Never
never类型表示永不存在的值的类型。比如那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型。
function error(): never {
throw new Error('Oops...);
}
let neverVar = (): never => { while (true) { } }
never类型是任何类型的子类型,也可以赋值给任何类型;然而,没有类型是never的子类型或可以赋值给never类型(除了never本身之外)。 即使 any也不可以赋值给never。
11. 类型断言
有时候我们比编译器更清楚某一个值的类型,所以需要通过某种方式告诉编译器不进行特殊的数据检查和解构,手动的去指定一个值的类型(好比其它语言里的类型转换),这种方式称之为类型断言。
类型断言有两种方式:
- <类型>值
let str: string = 'sina'
let len: number = (<string>str).length
- 值 as 类型
let str: stirng = 'sina'
let len: number = (str as string).length
注意:在tsx语法中必须使用 as
,否则tsx会把方式当作标签去解析。
实例:
当 TypeScript 不确定一个变量到底是哪个类型的时候,只能访问此变量联合类型里共有的属性或方法,但有时我们确实需要在还不确定类型的时候就访问其中一个类型的属性或方法,如下:
function getLength(str: string | number): number {
if (str.length || str.length === 0) {
return str.length
}
return str.toString().length
}
// Property 'length' does not exist on type 'string | number'. Property 'length' does not exist on type 'number'.
以上代码本身没有问题,在逻辑在都做了兼容性判断,但是ts在编译时会去判断str的联合类型是否都存在length属性,编译结果是str为number时不存在length属性,所以会抛出错误。
此时就可以使用类型断言将参数str断言成string类型。如下:
function getLength(str: string | number): number {
if ((<string>str).length || (str as string).length === 0) {
return (str as string).length
}
return str.toString().length
}
注意:类型断言不是类型转换,断言成一个联合类型中不存在的类型是不允许的:
function getLength(str: string | number): number {
return (str as boolean).length
}
// Property 'length' does not exist on type 'boolean'. return (str as boolean).length