一文上手 TypeScript 基础
TypeScript 是 JavaScript 的超集,在 JavaScript 的基础上增加了静态类型检查。
数据类型
TypeScript 具有 JavaScript 的所有类型,包括 boolean, number, string, undefined, null, symbol 及 object, 并增加了 enum, tuple, void, any 和 never 这几种类型。
1. TypeScript 中的基础类型
基础类型包括 boolean, number, string, undefined, null, symbol,对应 JavaScript 的原始数据类型。在 TypeScript 中声明也很方便,具体看下面的实例。
// boolean
let show: boolean = true
// number
let num: number = 1
// string
let name: string = 'myname'
// undefined
let u: undefined = undefined
// null
let n: null = null
undefined
和 null
是所有类型的子类型。类似下面这样赋值不会报错。
let u: undefined = undefined
let num: number = u
2. 数组
常见的定义数组的方式有两种
- 用
<elemType>+[]
表示和约束数组, - 用
Array<elemType>
数组范型来表示数组。
// elemType + []
let arr: number[] = [1, 2, 3, 4, 5]
// Array<elemType>
let arr:Array<number> = [1, 2, 3, 4, 5]
// 任意类型
let arr: any[] = ['a', 2, null]
3. 枚举
enum
类型可以赋予一组取值有意义的名字,可以用来创建有区别的用例。
枚举成员被赋予值为从 0
开始递增的数字,同时进行反向映射。
enum Direction {
Up,
Right,
Down,
Left,
}
Direction['Up'] === 0 // true
// 反向映射
Direction[0] === 'Up' // true
也可以手动赋值,未赋值的枚举项接着上一个递增。
enum Direction {
Up = 1,
Right,
Down,
Left,
}
Direction['Right'] === 2 // true
4. 元组
Tuple
类型可以用来表示已知元素数量和类型的数组,并且类型不必相同。
let person: [string, number] = ['myname', 20]
5. void, any 和 never
在 TypeScript
中可以用
void
表示没有任何返回值的函数,any
表示返回任何类型的值,never
表示永远不存在返回值的函数或者永不为真的变量。
// void
const foo: void = () => {
console.log('foo')
}
// any
let anyThing: any = 'jieiyi'
// never
// 示例暂定
7. 函数
常用的定义函数的方式有
- 函数声明
- 函数表达式
// 函数声明
function add(x: number, y: number): number {
return x + y
}
// 函数表达式
const add = (x: number, y: number): number => {
return x + y
}
// 可选参数
const add = (x: number, y: number, z?: number): number => {
if (z) {
return x + y + z
} else {
return x + y
}
}
8. 类
8.1 公共/私有/受保护修饰符(public/private/protected)
这几种修饰符都可以修饰属性和方法,各自效果如下,
public
默认修饰符,无限制。private
限制在类的外部访问,不能继承。protected
限制外部访问,但可被继承。
// public
class Girl {
public name: string
constructor(name: string) {
this.name = name
}
}
const myname = new Girl('myname')
console.log(myname) // myname
// 以上的写法也可以简化,仅在需要的时候指定修饰符
class Girl {
constructor(public name: string) {
this.name = name
}
}
// private
class Girl {
constructor(private name: string) {
this.name = name
}
}
const myname = new Girl('myname')
console.log(myname) // 编译错误
// protected
class Girl {
constructor(protected name: string) {
this.name = name
}
}
class TeenGirl extends Girl {
constructor(name: string, private age: number) {
super(name)
this.age = age
}
public getMessage = () => {
return `${this.name}: ${this.age}`
}
}
const myname = new TeenGirl('myname', 18)
console.log(myname.getMessage()) // myname: 18
console.log(myname.name) // 编译错误
8.2 只读修饰符(readonly)
设置属性为只读,只有在声明或者构造函数中被初始化,不能在外部改变。
class Girl {
constructor(readonly name: string) {
this.name = name
}
}
const myname = new Girl('myname')
myname.name = 'myname' // 编译错误
8.3 抽象修饰符(abstract)
定义抽象类,定义其他继承子类的基类。
- 抽象类不能被实例化。
- 抽象类中的抽象方法必须被子类实现。
abstract class Girl {
constructor(readonly name: string) {
this.name = name
}
// 定义抽象方法
abstract getMessage()
}
class TeenGirl extends Girl {
constructor(name: string, private age: number) {
super(name)
this.age = age
}
// 必须实现 Girl 类中定义的 getMessage 方法
public getMessage = () => {
return `${this.name}: ${this.age}`
}
}
const myname = new TeenGirl('myname', 18)
类型的复杂操作
1. 类型推论
TypeScript
会在没有指定类型的时候推测出一个类型,这就是类型推论。
let name = 'myname'
name = 007 // 编译错误,默认推论 name 的类型为 string
2. 联合类型
取值可以是多种类型中的一种。当访问联合类型的属性和方法的时候只能访问共有属性和方法。
let name: string | number
name = 'myname'
name = 007
// 访问属性和方法
const getName = (name: string | number): string => {
return name.toString() // toString 方法是 string 和 number 属性共有的
}
const getNameLen = (name: string | number): number => {
return name.length() // length 方法不是 string 和 number 属性共有的,会编译错误
}
3. 类型别名
可以给类型取一个新名字。用 type
修饰符创建别名。
type nameType = string | number
let name: nameType
name = 'myname'
name = 007
4. 字符串字面量
约束取值只能为给定的字符串。
type EventNames = 'click' | 'scroll'
const handleEvent = (element: Element, event: EventNames): any => {
element.addEventListener(event, () => {
event === 'click' && element.style.filter = 'grayscale(1)'
})
}
handleEvent(document.querySelector('html'), 'click')
5. 类型断言
用来手动指定一个值的类型。
- value
- TSX 中一般用
as
关键字。
const getNameLen = (name: string | number): number => {
if (name as string) {
return name.length
} eles {
name.toString().length
}
}
TypeScript 进阶
1. 接口(Interface)
通过接口来约束对象的类型。
1.1 对象与接口
通过接口来描述对象的形状。
- 变量形状必须与接口保持完全一致
?
可用来表示可选属性- 诸如
[propName: string]
的方法可以加入任意属性,但确定属性和可选属性的类型都必须是它的类型的子集
interface IGirl {
name: string | number
age?: number
[propName: string]: any
}
const myname: IGirl {
name: 'myname',
age: 18,
fruit: 'strawberry',
}
2. 泛型
在定义对象的时候不预先指定具体类型,而是在使用的时候才指定。
2.1 示例: echo 命令
echo
命令是一个传声筒,会原样返回任何它传入的值。
// 希望效果
echo('myname') // myname
echo(007) // 007
上面传入了 string
类型和 number
类型,简单写法可以如下,
const echo = (value: any): any => value
不过显而易见,我们丢失了返回值的类型。采用泛型,可以很好的解决这个问题。
const echo<T> = (value: T): T => value
上面函数中,给函数 echo
添加了类型变量 T
,T
帮助捕获用户传入值的类型,并传给函数,最后传给函数值。现在我们明确知道返回值的类型了。
参考
转载自:https://juejin.cn/post/7267539993966821411