初学typescript
Posted wangxi01
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了初学typescript相关的知识,希望对你有一定的参考价值。
前言
ts有多火大家也知道,惭愧的是,我现在还对它不熟悉,今天就开始学习一下吧。
typescript
的数据类型
相比于ES6
的数据类型来说,typescript
拥有了新的几种数据类型,它们分别是void
、any
、never
、元组
、枚举
以及其它的一些高级类型。
在typescript
中,我们定义一个变量时,需要指定它的类型(当然不指定的话ts
也会进行类型推断),它的写法如下:
//原始类型
let bool:boolean = true
let num:number = 123
let str:string = ‘abc‘
// 数组
let arr1: number[] = [1, 2, 3]
let arr2: Array<number | string> = [1, 2, 3, ‘2‘]
// 元组 可以为元组添加数据,但无法访问
let tuple: [number, string] = [0, ‘1‘]
// tuple.push(2)
// console.log(tuple)
// tuple(2)
// 函数
let add = (x: number, y:number): number => x + y
let compute: (x: number, y: number) => number
compute = (a, b) => a + b
// 对象
let obj: {x: number, y: number} = {x: 1, y: 2}
obj.x = 3
// symbol
let s1: symbol = Symbol()
let s2 = Symbol()
console.log(s1 === s2)
// undefined, null
let un: undefined = undefined
let nu: null = null
// void 没有返回值
let noReturn = () => {}
// any
let x
// never 永远不会有返回值的类型
let error = () => {
throw new Error(‘error‘)
}
let endless = () => {
while(true){}
}
枚举
一组有名字的常量的集合。
你可以把它当成一个通讯录,在拨打电话的时候只需要记住人名就可以了,而不需要去记得它的电话号码,而且电话号码是经常变化的,而人名基本不会发生变化。
为什么使用枚举?
我们可以使用枚举定义一些带名字的常量,也可以清晰地表达意图或创建一组有区别的用例。
如下例子,我们写了一个对角色进行判断的方法:
function initByRole (role){
if(role === 1 || role === 2){
// do sth
}else if(role === 3 || role === 4){
// do sth
}else if(role === 5){
// do sth
}else {
// do sth
}
}
但是它是存在问题的:
- 可读性差:如果没有文档,我们很难记住这些数字的含义
- 可维护性差: 硬编码,牵一发而动全身
如果我们使用枚举呢?我们可以这样写:
const enum RoleEnum{
Reporter = 1,
Developer,
Maintainer,
Owner,
Guest
}
function initByRole(role: RoleEnum) {
if (role === RoleEnum.Reporter || role === RoleEnum.Developer) {
// do sth
} else if (role === RoleEnum.Maintainer || role === RoleEnum.Owner) {
// do sth
} else if (role === RoleEnum.Guest) {
// do sth
} else {
// do sth
}
}
枚举有哪些?
- 数字枚举
enum Role {
Reporter,
Developer,
Maintainer,
Owner,
Guest
}
- 字符串枚举
enum Message {
Success = ‘恭喜你,成功了‘,
Fail = ‘抱歉,失败了‘
}
- 异构枚举(不推荐)
从技术的角度来说,枚举可以混合字符串和数字成员:
enum Answer {
N,
Y = ‘yes‘
}
- 枚举成员
enum Char {
// 常量成员
a,
b = Char.a,
c = 1 + 2,
// 计算成员
// computed不会在编译阶段计算,会被保留到执行阶段,在这后面定义的枚举成员必须有初始值才不会报错
d = Math.random(),
e = ‘123‘.length
}
- 常量枚举
const enum Month {
Jan,
Feb,
Mar
}
let month = [Month.Jan, Month.Feb, Month.Mar] //var month = [0 /* Jan */, 1 /* Feb */, 2 /* Mar */];
- 有时枚举和枚举成员都可以作为一种类型存在
enum E { a, b}
enum F { a = 0, b = 1}
enum G { a = ‘apple‘, b = ‘banana‘ }
//枚举作为了类型
let e: E = 3
let f: F = 3
//枚举成员作为了类型
let e1: E.a
let e2: E.b
let e3: E.a
let g1: G
let g2: G.a
接口
这个接口可不是我们平时写业务代码时请求后台数据的那个接口啊,那这个接口是什么呢?
接口是一系列抽象方法的声明,是一些方法特征的集合,这些方法都应该是抽象的,需要由具体的类去实现,然后第三方就可以通过这组抽象方法调用,让具体的类执行具体的方法。
简单的说呢,就是它定义了一些属性、函数、可索引和类的所需要遵守的规范,然后自己就相当于变成了一种类型,去对值所具有的结构进行类型检查。
对象类型接口
interface List {
id: number;
name: string;
}
interface Result {
data: List[]
}
function render(result: Result){
result.data.forEach((value) => {
console.log(value.id, value.name)
})
}
let result = {
data: [
{
id: 1,
name: ‘A‘
},
{
id: 2,
name: ‘B‘
}
]
}
render(result)
这是一个打印数组对象id
和name
的方法,没毛病,如果我们此时修改一下result
的结构,增加一个变量:
let result = {
data: [
{
id: 1,
name: ‘A‘,
sex: ‘male‘
},
{
id: 2,
name: ‘B‘
}
]
}
ts
不会报错,因为TypeScript
的核心原则之一是对值所具有的结构进行类型检查。 它有时被称做“鸭式辨型法”或“结构性子类型化”。就是说,如果一只鸟,看起来像鸭子,游起来像鸭子,叫起来像鸭子,那这只鸟就可以被认为是鸭子。
我们只要传入的对象满足接口的必要条件,就是被允许的,即使传入了多余的字段,也可以通过类型检查。但也有一个例外,如果我们直接传入对象字面量,ts
就会对额外的字段进行检查:
//有警告
render({
data: [
{
id: 1,
name: ‘A‘,
sex: ‘male‘
},
{
id: 2,
name: ‘B‘
}
]
})
想绕过这种检查的话,有三种方法:
- 像之前那样,用一个变量存储起来
- 使用类型断言
render({
data: [
{
id: 1,
name: ‘A‘,
sex: ‘male‘
},
{
id: 2,
name: ‘B‘
}
]
} as Result)
// 也可以这样,两者等价,但推荐上面那种,因为下面这种在react中可能导致歧义
render(<Result>{
data: [
{
id: 1,
name: ‘A‘,
sex: ‘male‘
},
{
id: 2,
name: ‘B‘
}
]
})
- 字符串索引签名
interface List {
readonly id: number;
name: string;
[x: string]: any
}
可索引类型接口
// 用任意的数字去索引StringArray,得到的都是string
interface StringArray {
[index: number]: string
}
let char: StringArray = [‘A‘, ‘B‘]
interface Names {
[x: string]: string;
// y: number 不能再声明number类型成员
[z: number]: string //数字索引签名的返回值一定要是字符串索引签名返回值的子类型,因为会进行类型转换,number转换为string,这样可以保持类型的兼容
}
// => 所以数字索引如果返回数字,字符串索引返回就需要更大范围
interface Names2 {
[x: string]: any;
[z: number]: number
}
函数类型接口
接口能够描述javascript
中对象拥有的各种各样的外形。 除了描述带有属性的普通对象外,接口也可以描述函数类型。
interface Lib {
(): void;
version: string;
doSomething(): void;
}
function getLib() {
let lib: Lib = (() => { }) as Lib
lib.version = ‘1.0‘
lib.doSomething = () => { }
return lib
}
let lib1 = getLib()
lib1()
lib1.doSomething()
ts
还是要在实战中多多使用才能融会贯通,目前只是熟悉,大致了解ts
的写法与基本用法,慢慢来。
以上是关于初学typescript的主要内容,如果未能解决你的问题,请参考以下文章
typescript Angular最终版本的Angular 2测试片段。代码库https://developers.livechatinc.com/blog/category/programming
typescript Angular最终版本的Angular 2测试片段。代码库https://developers.livechatinc.com/blog/category/programming