1.数据类型
1.基础数据类型
ts不能被浏览器理解,需要编译成js,可以理解是js的超集
注意数据类型都是小写的
boolean
number
string
undefined
null
默认情况下null和undefined是所有类型的子类型,可以把null和undefined赋值给number等其他类型的变量
let age: number = null;
let name: string = undefined;
any
不清楚用什么类型,可以使用 any 类型,意思就是啥都可以,不建议
unknown
代表任何类型,是一个安全类型,推荐,可以配置断言使用
function divide(param: unknown) {
return param as number / 2;
}
void
标识没有任何返回值,这个应该很熟悉
2.数组/元组/对象/函数
数组类型
let list: number[] = [1,2,3]; // 不限定数量
list.push(4);
元组类型
元组类型表示已知元素数量和类型的数组
let arr: [number, string] = [20, 'yuping'];
可以使用push方法,但是只能是指定的类型
函数类型
定义函数类型需要定义输入参数类型和输出类型,使用时注意:
参数后加个问号,代表这个参数是可选的;
可选参数要放在函数入参的最后;
可以在入参里面定义初始值;
ts中函数不可以直接复制,举个栗子:
let add1 = (x: number, y: number): number => {
return x + y;
}
let add2: (x: number, y: number) => number = add1; // 即要定义变量的类型
函数重载:函数名称相同,参数个数或者类型不同,一般用泛型解决
interface类型,可以用来定义对象或者数组
定义interface一般首字母大写
interface Person {
readonly id: number
name?: string
age: number
}
interface Sum {
(x: number, y: number): number
}
const mySum: Sum = (x, y) => {
return x + y;
}
假如一个对象上面有很多不确定的属性,可以自定义属性
interface RandomKey {
[propName: string]: string
}
const instance: RandomKey = {
age: '20',
name: 'yuping',
};
interface likeArr {
[propName: number]: string
}
const arr: likeArr = ['20', 'yuping'];
因为interface很灵活,所以它有个响亮的名字叫鸭子类型(duck typing)
3.面向对象部分
1.public private protected static
public共有的
private私有的,只在类的内部可访问,实例和子类不能访问
protected保护的,类的内部和子类内部可以访问,实例不能访问
static静态的,只能通过类名访问
2.abstract抽象类
只能被继承,不能实例化的类就叫做抽象类,抽象类中的抽象方法必须被继承的子类实现
abstract class Animal {
construct(name: string) {
this.name = name;
}
name: string
abstract sayHi(): void
}
class Dog extends Animal {
construct(name: string) {
super(name);
}
sayHi() {
console.log('hello');
}
}
抽象类的用法是用来定义一个基类,声明共有属性和方法,拿去被继承,有利于实现多态
所谓多态就是父类定义的一个抽象方法,在子类中有不同的实现
3.implements实现
有时候具有相同功能的类并不具有相同的父类,所以通过抽象类继承的方式就会有问题
interface原本是设计用来定义对象类型的,但是也可以用来约束class
interface MusicInterface {
playMusic(): void
}
class CellPhone implements MusicInterface {
playMusic() {
console.log('playing music');
}
}
implements只能约束类实例上的属性和方法,要约束构造函数和静态属性,需要这么写
interface CircleStatic {
new (radius: number): void
pi: number
}
const Cirlce: CircleStatic = class Cirlce {
construct(radius: number) {
this.radius = radius;
}
radius: number
static pi: 3.14
}
4.枚举类型enum
相当于创建了一个code到name的映射关系
enum Direction {
left = '100',
right = 20,
up = 15,
down = '23',
}
console.log(Direction.left); // '100'
console.log(Direction.right); // 20
console.log(Direction.up); // 15
console.log(Direction.down); // '23'
console.log(Direction['100']); // left
console.log(Direction[20]); // right
console.log(Direction[15]); // up
console.log(Direction['23']); // down
5.内置类型
Array Date Error RegExp HTMLElement NodeList MouseEvent等等
2.进阶内容
1.联合类型 交叉类型 type类型别名
联合类型 |
let num: string | number
当TS不确定一个联合类型的变量到底是哪个类型的时候,只能访问他们共有的属性和方法
交叉类型 &
interface Person {
name: string
age: number
}
type Student = Person & { grade: number }
类型别名type:类似于用var定义变量
type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
type和interface的区别
interface使用extends实现继承, type使用交叉类型实现继承
interface的声明会被合并,但是type不会
2.类型断言as
使用类型断言来告诉TS,我(开发者)比你(编译器)更清楚这个参数是什么类型,你就别给我报错了,举个栗子
function getLength(arg: number | string): number {
const str = arg as string;
if (str.length) {
return str.length;
} else {
const number = arg as number;
return number.toString().length;
}
}
注意类型断言不是类型转换
3.字面量(常量)类型
type ButtonSize = 'mini' | 'small' | 'normal' | 'large';
const myButtonSize = 'small';
4.泛型<>
可以用来保持输入输出的一致性,可以理解是在定义时候类型的一个占位符,使用的时候把实际的类型传递进去(这不就是参数传值吗),一看到<>就知道是泛型。下面是泛型的很多栗子
处理多个函数参数
function swap<T, U>(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]];
}
希望调用api可以清晰的知道返回的数据结构
interface UserInfo {
name: string
age: number
}
function request<T>(url:string): Promise<T> {
return fetch(url).then(res => res.json());
}
request<UserInfo>('user/info').then(res => {
console.log(res);
})
对于泛型进行约束,通过继承实现
interface ILength {
length: number
}
function printLength<T extends ILength>(arg: T): T {
console.log(arg.length);
return arg;
}
泛型约束数组
const arr: Array<number> = [1,2,3];
泛型约束class
class Stack<T> {
private data: T[] = []
push(item: T) {
return this.data.push(item);
}
pop(): T | undefined {
return this.data.pop();
}
}
const s1 = new Stack<number>();
泛型约束interface
interface IKeyValue<T, U> {
key: T
value: U
}
const k1: IKeyValue<number, string> = { key: 18, value: 'lin' };
const k2: IKeyValue<string, number> = { key: 'lin', value: 18 };
3.ts结合vue3
申明类型的两种方式:运行时申明和基于类型的申明
1.props
基于类型的声明props需要使用withDefaults设置默认值
export interface Props {
msg?: string
labels?: string[]
}
const prosp = withDefaults(defineProps<Props>(), {
msg: 'hello',
labels: () => ['one', 'two']
})
2.emits
<script setup lang="ts">
// 运行时
const emit = defineEmits(['change', 'update']);
// 基于类型
const emit = defineEmits<{
(e: 'change', id: number): void
(e: 'update', value: string): void
}>();
</script>
3.ref
const year = ref<string | number>('2020');
year.value = 2020; // 成功!
4.reactive
import { reactive } from 'vue';
interface Book {
title: string
year?: number
}
const book: Book = reactive({ title: 'Vue 3 指引' });
5.computed
const double = computed<number>(() => {
// 若返回值不是 number 类型则会报错
});
6.事件处理函数
官方栗子
<script setup lang="ts">
function handleChange(event: Event) {
console.log((event.target as HTMLInputElement).value);
}
</script>
<template>
<input type="text" @change="handleChange" />
</template>
7.provide/inject
通过symbol注入,需要配合InjectionKey
import { provide, inject } from 'vue';
import type { InjectionKey } from 'vue';
const key = Symbol() as InjectionKey<string>;
provide(key, 'foo'); // 若提供的是非字符串值会导致错误
const foo = inject(key); // foo 的类型:string | undefined
通过字符串注入,带默认值
const foo = inject<string>('foo', 'bar'); // 类型:string | undefined
8.模板引用
<script setup lang="ts">
import { ref, onMounted } from 'vue';
const el = ref<HTMLInputElement | null>(null);
onMounted(() => {
el.value?.focus();
})
</script>
<template>
<input ref="el" />
</template>
9.组件模板引用
<!-- MyModal.vue -->
<script setup lang="ts">
import { ref } from 'vue';
const isContentShown = ref(false);
const open = () => (isContentShown.value = true);
defineExpose({
open,
})
</script>
<!-- App.vue -->
<script setup lang="ts">
import MyModal from './MyModal.vue';
const modal = ref<InstanceType<typeof MyModal> | null>(null);
const openModal = () => {
modal.value?.open();
}
</script>
typeof + InstanceType