本文只对常用的ts语法进行推荐,其他的语法根据自己需要,自行学习剖析
安装
使用npm全局安装typescript
(如果出现报错,大概率是因为权限不够导致的,使用管理员权限进行安装)
npm i -g typescript
运行
将ts文件生成为对应的js文件
(node无法直接运行ts文件,所以如果用node运行,要用下面的命令先生成js文,如针对test.ts使用如下命令,可自动生成test.js的文件)
tsc test.ts
node运行ts文件
ts-node test.ts
简单数据类型
简单数据类型number约束
let decimal: number = 6;
简单数据类型boolean约束
let isDone: boolean = false;
简单数据类型string约束
let color: string = "blue";
任意类型或未知
any数据类型,慎用,一般不推荐使用,使用any会失去类型校验
let d: any = 4;
unknown数据类型,可以理解为安全的any,不推荐使用
let notSure: unknown = 4;
复杂类型
复杂类型数组校验
let list: number[] = [1, 2, 3];
或者
const list:Array<number> = [1,2,3]
enum,枚举,TS中新增类型
enum Color {
Red,
Green,
Blue,
}
let c: Color = Color.Green;
void类型,多用于函数无返回值的情况
function handleAdd(num1:number,num2:number):void {
this.sum =num1+num2
}
定义对象其余所有参数,如下,obj里除name为string外,其余参数键为字符串,值为number类型
let obj:{name:string,[propName:string]:number}
类型断言
对于一个数据,可能为多个类型或者未知类型的时候,但是我们只需要特定的类型的属性时,进行断言,断定为我们需要的类型
let someValue: unknown = "this is a string";
let strLength: number = (someValue as string).length;
非空断言
在上下文中当类型检查器无法断定类型时,可以使用操作符 !
进行断言操作对象是非 null 和非 undefined 的类型,即x!的值不会为 null 或 undefined
let user: string | null | undefined;
console.log(user!.toUpperCase()); // 编译正确
console.log(user.toUpperCase()); // 错误
确定赋值断言
let value:number
console.log(value); // Variable 'value' is used before being assigned.
我们定义了变量, 没有赋值就使用,则会报错
通过 let x!: number; 确定赋值断言,TypeScript 编译器就会知道该属性会被明确地赋值。
类class (用到的开发场景不多,建议只做了解)
定义类
class 类名 {
属性名: 类型;
constructor(参数: 类型){
this.属性名 = 参数;
}
方法名(){
....
}
}
示例:
class Person{
/*
* public(默认值),可以在类、子类和对象中修改,可省略
* protected ,可以在类、子类中修改
* private ,可以在类中修改
*/
public name: string;
public age: number;
constructor(name: string, age: number){
this.name = name;
this.age = age;
}
sayHello(){
console.log(`大家好,我是${this.name}`);
}
}
//继承
class Employee extends Person{
constructor(name: string, age: number){
super(name, age);
this.name = name; //只有父类数据为public或者protected,子类中可以修改父类数据
}
}
//使用类
const p = new Person('孙悟空', 18);
p.sayHello();
抽象类
抽象类是专门用来被其他类所继承的类,它只能被其他类所继承不能用来创建实例
使用abstract开头的方法叫做抽象方法,抽象方法没有方法体只能定义在抽象类中,继承抽象类时抽象方法必须要实现
abstract class Animal{
abstract run(): void;
bark(){
console.log('动物在叫~');
}
}
class Dog extends Animals{
run(){
console.log('狗在跑~');
}
}
接口(Interface)
示例(检查对象类型):
interface Person{
name: string;
sayHello():void;
}
function fn(per: Person){
per.sayHello();
}
fn({name:'孙悟空', sayHello() {console.log(`Hello, 我是 ${this.name}`)}});
type 类型别名
type myType = string|number;
type menuListType={
menuId:number;
meuName:syring
}
interface dataType {
menuList:menuListType[]
}
let m:myType
const data:dataType = {
menuList:[],
userInfo:[]
}
interface 和 type的异同
接口和类型别名都可以用来描述对象或函数的类型,只是语法不同
type MyTYpe = {
name: string;
say(): void;
}
interface MyInterface {
name: string;
say(): void;
}
相同点:
都允许扩展
interface 用 extends
来实现扩展;type 使用 &
实现扩展
interface MyInterface {
name: string;
say(): void;
}
interface MyInterface2 extends MyInterface {
sex: string;
}
type MyType = {
name:string;
say(): void;
}
type MyType2 = MyType & {
sex:string;
}
let person:MyInterface2 = {
name:'小明',
sex:'男',
say(): void {
console.log("hello 啊,小明!");
}
}
let value: MyType2 = {
name:'小明',
sex:'男',
say(): void {
console.log("hello 啊,小明!");
}
}
不同点
type可以声明基本数据类型别名/联合类型/元组等,而interface不行
// 基本类型别名
type UserName = string;
type UserName = string | number;
// 联合类型
type Animal = Pig | Dog | Cat;
type List = [string, boolean, number];
interface能够合并声明,而type不行
interface Person {
name: string
}
interface Person {
age: number
}
// 此时Person同时具有name和age属性
联合类型
联合类型用|
分隔,表示取值可以为多种类型中的一种
let name:string|number
status='小虾米'
status=100
交叉类型
交叉类型就是跟联合类型相反,用&
操作符表示,交叉类型就是两个类型必须存在
注意:交叉类型取的多个类型的并集,但是如果key相同但是类型不同,则该key为never类型
interface PersonA{
name: string,
age: number
}
interface PersonB {
name: string,
gender: string
}
//person 即是 PersonA 类型,又是 PersonB 类型
let person: PersonA & PersonB = {
name: "龟仙人",
age: 88,
gender: "男"
};
类型守卫
类型守卫是运行时检查,确保一个值在所要类型的范围内
目前主要有四种的方式来实现类型保护:
in 关键字
interface InObj1 {
a: number,
x: string
}
interface InObj2 {
a: number,
y: string
}
function isIn(arg: InObj1 | InObj2) {
// x 在 arg 打印 x
if ('x' in arg) console.log('x')
// y 在 arg 打印 y
if ('y' in arg) console.log('y')
}
isIn({a:1, x:'xxx'});
isIn({a:1, y:'yyy'});
typeof 关键字
function isTypeof( val: string | number) {
if (typeof val === "number") return 'number'
if (typeof val === "string") return 'string'
return '啥也不是'
}
instanceof关键字(作了解)
function creatDate(date: Date | string){
console.log(date)
if(date instanceof Date){
date.getDate()
}else {
return new Date(date)
}
}
自定义类型保护的类型谓词(作了解)
function isNumber(num: any): num is number {
return typeof num === 'number';
}
function isString(str: any): str is string{
return typeof str=== 'string';
}
泛型(Generic)
定义一个函数或类时,有些情况下无法确定其中要使用的具体类型(返回值、参数、属性的类型不能确定),此时泛型便能够发挥作用。
这里的<T,K>
就是泛型,T是我们给这个类型起的名字(不一定非叫T或者K),设置泛型后即可在函数中使用T或者K来表示该类型。所以泛型其实很好理解,就表示某个类型。即:传入的是什么类型,那泛型就是什么类型
function test<T, K>(a: T, b: K): K{
return b;
}
test<number, string>(10, "hello");
泛型接口
在定义接口的时候指定泛型
interface KeyValue<T,U> {
key: T;
value: U;
}
const person1:KeyValue<string,number> = {
key: '小明',
value: 18
}
const person2:KeyValue<number,string> = {
key: 20,
value: '张麻子'
}
泛型类
class Test<T> {
value: T;
add: (x: T, y: T) => T;
}
let myTest = new Test<number>();
myTest.value = 0;
myTest.add = function (x, y) {
return x + y;
};
泛型类型别名
type Cart<T> = { list: T[] } | T[];
let c1: Cart<string> = { list: ["1"] };
let c2: Cart<number> = [1];
泛型参数的默认类型
我们可以为泛型中的类型参数指定默认类型。当使用泛型时没有在代码中直接指定类型参数,从实际值参数中也无法推测出时,这个默认类型就会起作用。
function createArray<T = string>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
泛型工具类型
typeof 推出类型
//先定义变量,再定义类型
let p1 = {
name: "小明",
age: 18,
gender: "male",
};
type People = typeof p1;
function getName(p: People): string {
return p.name;
}
getName(p1);
keyof 可以用来获取一个对象接口中的所有 key 值
interface Person {
name: string;
age: number;
gender: "male" | "female";
}
type PersonKey = keyof Person; //type PersonKey = 'name'|'age'|'gender';
function getValueByKey(p: Person, key: PersonKey) {
return p[key];
}
let val = getValueByKey({ name: "小明", age: 18, gender: "male" }, "name");
console.log(val); // 小明
in 用来遍历枚举类型:
type Keys = "a" | "b" | "c"
type Obj = {
[p in Keys]: any
} // -> { a: any, b: any, c: any }
extends 对泛型的范围进行约束,泛型T必须是MyInter的子类,不一定非要使用接口类,抽象类同样适用。
//现在这个泛型函数被定义了约束,因此它不再是适用于任意类型:
interface MyInter{
length: number;
}
function test<T extends MyInter>(arg: T): number{
return arg.length;
}
test(3);// Error, number doesn't have a .length property
test({length: 10, name: '张麻子'}); // 当我们传入合法的类型的值,即包含 length 属性的值时,编译正确
infer 在条件类型语句中,可以用 infer 声明一个类型变量并且对它进行使用。(了解)
//infer R 就是声明一个变量来承载传入函数签名的返回值类型,简单说就是用它取到函数返回值的类型方便之后使用。
type ReturnType<T> = T extends (
...args: any[]
) => infer R ? R : any;
使用 [] 操作符可以进行索引访问:
interface Person {
name: string;
age: number;
}
type x = Person["name"]; // x is string
TS中常用的高级内置工具类型
Partial集体可选(将类型定义的所有属性都修改为可选。)(重点)
checkInData: Partial<{
today_sign: number;
series_days: number;
}>;
上面的代码相当于
checkInData:{
today_sign?: number;
series_days?: number;
}
Record 简单对象键值对,所有类型指定(重点)
以 typeof 格式快速创建一个类型,此类型包含一组指定的属性且都是必填。
//示例1,对象的键必须为'x'或者'y',键值必须为数字类型:
type Coord = Record<'x' | 'y', number>;
// 等同于
type Coord = {
x: number;
y: number;
}
//示例2:
//activity对象,第一个参数为key,必须为字符串,第二个参数为key值,必须为数字
activity: Record<string, number>;
Readonly 将所有属性定义为只读(重点)
type Coord = Readonly<Record<'x' | 'y', number>>;
// 等同于
type Coord = {
readonly x: number;
readonly y: number;
}
// 如果进行了修改,则会报错:
const c: Coord = { x: 1, y: 1 };
c.x = 2; // Error: Cannot assign to 'x' because it is a read-only property.
pick 选取部分类型校验(重点)
如下:CoordX选取了Coord中的x组成一个新的type数据类型校验
type Coord = Record<'x' | 'y', number>;
type CoordX = Pick<Coord, 'x'>;
// 等用于
type CoordX = {
x: number;
}
Omit 与Pick相反,Omit<T,K> 从T中取出除去K的其他所有属性。
interface Person {
name: string,
age: number,
gender: string
}
type P1 = Omit<Person, "age" | "gender">
const user:P1 = {
name: '小明'
}
Required 集体必选(重点)
interface Person {
name?: string,
age?: number,
hobby?: string[]
}
const user: Required<Person> = {
name: "小明",
age: 18,
hobby: ["code"]
}
InstanceType 返回构造函数类型C的实例类型,常用于获取组件实例
class C {
x = 0;
y = 0;
}
type D = InstanceType<typeof C>; // C
Exclude 将某个类型中属于另一个的类型移除掉,剩余的属性构成新的类型
type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
type T1 = Exclude<"a" | "b" | "c", "a" | "b">; // "c"
type T2 = Exclude<string | number | (() => void), Function>; // string | number
Extract 和 Exclude 相反,Extract<T,U>
从 T 中提取出 U。适用于:并集类型 (了解)
type T0 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
type T1 = Extract<string | number | (() => void), Function>; // () =>void
NonNullable 去除类型中的 null
和 undefined
(了解)
type P1 = NonNullable<string | number | undefined>; // string | number
type P2 = NonNullable<string[] | null | undefined>; // string[]
ReturnType 用来得到一个函数的返回值类型 (了解)
type Func = (value: string) => string;
const test: ReturnType<Func> = "1";
Parameters 用于获得函数的参数类型所组成的元组类型。(了解)
type P1 = Parameters<(a: number, b: string) => void>; // [number, string]
以下为TS+vue3的部分开发语法
详情请移步至vue3.0+TS文章查看:vue3.0+TS使用_零凌林的博客-CSDN博客
ts+ref
const show = ref<boolean>(false);
ts+reactive
type menuListType={
menuId:number;
meuName:syring
}
interface dataType {
menuList:menuListType[]
}
const data =reactive<dataType>({
menuList:[],
userInfo:[]
})
或者
const data:dataType =reactive({
menuList:[],
userInfo:[]
})
获取组件 ref 实例+ts
使用 vue3 和 ts 时,为了获取 组件 ref 实例,就需要在 ref 函数的泛型中指定类型。如何获取组件的类型呢?vue 官方文档中 TypeScript 支持里已经告诉我们了一个获取组件类型的方法,InstanceType<typeof 组件名称>,使用方式如下:
const $userForm = ref<InstanceType<typeof userForm>>();
ts ref实例
//子组件
<NewsDialog ref="news" @refreshData="getList()"></NewsDialog>
//导入子组件
import NewsDialog from './components/NewsDialog.vue'
//获取子组件实例
const news = ref<InstanceType<typeof NewsDialog>>()
//打开消息弹窗
const openNewsDialog = (): void => {
news.value?.showDialog()
}
获取原生dom的ref实例
//input标签
<input
type="text"
class="search"
ref="input"
v-model="inputValue"
placeholder="队伍名称最多6个字"
maxlength="6"
/>
const input = ref<HTMLElement | null>(null);
//获取焦点
(input.value as HTMLInputElement).focus();
ts结合emit使用
//之前的写法
const emit = defineEmits(['change', 'update'])
//ts写法
const emit = defineEmits<{
(e:'change'):void,
(e:'update',value:string):void
}>
ts结合prop使用
//之前的写法
const prop = defineProps({
id:{
type:Number,
default:0
}
})
//ts写法
interface PropType = {
id:number
}
const prop = defineProps<PropType>()
tips:以下作为了解,当我们使用vant组件库官方推荐的自动引入组件的方法时需注意:
Vant 中有个别组件是以函数的形式提供的,包括 Toast,Dialog,Notify 和 ImagePreview 组件。在使用函数组件时,unplugin-vue-components 无法自动引入对应的样式,因此需要在需要的页面里手动引入样式。
import { Dialog } from 'vant';
const VanDialog = Dialog.Component;