环境配置
1 2 3 4 5
| npm install -g typescript
tsc demo.ts
tsc -w demo.ts
|
安装报错就用npx
1 2 3
| npm i -g ts-node@8.5.4 npx tsc npx ts-node abc.ts
|
静态类型 基础静态类型和对象静态类型
一旦定义不可改变
基础数据类型相同
- string
- number
- null
- undefined
- bollean
- void
- symbol
count会继承number类型的方法
1 2 3
| let count :number = 1; count = 2 count.toFixed(2)
|
赋值为一个数组 数组的值必须为string类型
1
| const man : string[] = ['a','b','c']
|
自定义静态类型 接口定义
如果类型错误会报错
1 2 3 4 5 6 7 8
| interface Person { uname : String, age : number } let man :Person = { uname : 'xiaogang', age : 100 }
|
demo2
1 2 3 4 5 6 7 8
| const person : { uname : string, age : number } = { uname : 'ahua', age : 66 } console.log(person)
|
函数定义
any
使用any会导致类型检查失效 所以不建议使用any
1 2
| const func :(a:any)=>any = (a:any)=>{return 'a'}
|
类型是一个函数 返回值必须是一个字符串
1
| const func :()=>string = ()=>{return 'a'}
|
定义一个没有返回值的函数
1
| const func :()=>void = ()=>{console.log('a')}
|
如果一直执行不完的函数要返回never
1 2 3 4 5 6 7 8
| function error() :never{ throw Error() console.log('err'); } function whileFunc() :never{ while(true){} console.log('while'); }
|
函数参数如果是对象的话 参数的类型需要成对象的形式设定类型
此处如果total直接定义类型 不在函数重定义类型 则函数返回值为其他类型也不会报错
const total :number = getTotal({a:1,b:2})
此处返回值为 ‘a2’并且不会报错
1 2 3 4
| function getTotal({a, b}:{a:number, b:number}){ return a + b } const total = getTotal({a:1, b:2})
|
类型注释和类型推断
类型注解
1 2
| let count :number; count = 1;
|
自动识别出count1的数据类型
1 2 3 4 5 6
| let count1 = 1; count1 = 'a'
const one = 1; const two = 2; const three = one + two;
|
此处因为ab可以是任意值所以 total不能判断出自己的类型
1 2 3 4 5
| function getTotal(a, b){ return a + b } const total = getTotal(1, 2) console.log(total)
|
此处ab设定了自己的类型 所以total也可以确定自己的类型
1 2 3 4 5
| function getTotal(a : number,b :number){ return a + b } const total = getTotal(1,2) console.log(total)
|
对象类型也可以自动推断
1 2 3 4
| const person = { uname : 'liuying', age : 18 }
|
可以推断出数据类型的变量就不需要注释
不可以推断出数据类型的变量就要加注释
数组类型的定义
1 2 3
| const numberArr :number[] = [1,2,3]; const stringArr :string[] = ['a','b','c'] const undefinedArr :undefined[] = [undefined]
|
多类型数组
1
| const arr :(number | string)[] = [1,'a']
|
数组套对象
1
| const person :{uname:string, age:number}[] = [{uname:'xiaoliu', age:18}]
|
类型别名
相当于把限制类型定义到一个参数中 也可以用class的方式
1 2 3 4 5 6
| type lady = {uname:string, age:number} const person :lady[] = [{ uname : 'xiaoliu', age : 18 }]
|
1 2 3 4 5 6 7 8 9
| class xiao { uname : string; age : number; } const person :xiao[] = [{ uname : 'xiaoliu', age : 18 }]
|
intreface 接口
接口定义类型别名和类型数据
1 2 3 4 5 6 7 8 9 10 11
| interface Girl { uname : string; age : number; xiong : number; yao ?: number; [propname:string]:any; say():string; }
|
直接设置变量值的类型
1 2 3 4 5 6 7 8 9
| const person :Girl = { uname : 'yingzi', age : 11, xiong : 80, yao : 50, say(){ return 'aaa' } }
|
传入变量值和变量值的类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function get(person:Girl){ if(person.age < 24 && person.xiong >= 80){ console.log('合格') }else{ console.log('不合格'); } } function getInfo(person:Girl){ console.log([ person.uname, person.age, person.xiong, person.yao ? person.yao : '' ]); } get(person) getInfo(person)
|
如此继承的类受interface的限制 接口必须的值类中必须存在
1 2 3 4 5 6 7 8 9
| class Xiaojie implements Girl{ uname : 'yingzi'; age : 11; xiong : 80; yao : 50; say(){ return 'aaa' } }
|
接口继承
1 2 3
| interface Teacher extends Girl{ teacher():string }
|
interface和type的区别
- interface 只能定义对象类型
- type 可以定义任意类型
定义的区别
1 2 3 4 5 6 7 8
| interface Person { name : string; age : number; } type Person1 = { name : string; age : number; }
|
扩展性
Interface 具有更强的扩展性,可以通过 extends 关键字进行扩展:
1 2 3 4 5 6 7
| interface Person { name: string; age: number; } interface Employee extends Person { salary: number; }
|
Type 也可以通过交叉类型(Intersection Types)进行扩展:
1 2 3 4 5 6 7
| type Person = { name: string; age: number; }; type Employee = Person & { salary: number; };
|
重新声明
interface会叠加 type不可重新声明(会报错// Error: Duplicate identifier ‘Person’.)
1 2 3 4 5 6 7 8 9 10 11
| interface Person { name: string; } interface Person { age: number; }
interface Person { name: string; age: number; }
|
定义联合类型和元祖
Interface 不能直接定义联合类型和元组。
Type 可以用来定义联合类型和元组:
1 2
| type Status = "success" | "error" | "loading"; type Point = [number, number];
|
使用场景
- Interface 通常用于定义对象的结构,特别是在定义类的形状时更常用。
- Type 更适合用于定义复杂的类型,比如联合类型、交叉类型或元组。
总结
- Interface 更适合用于定义对象的形状和结构,并且具有良好的扩展性。
- Type 更灵活,可以定义联合类型、元组以及使用映射类型,适合更复杂的类型定义。
元组的使用和类型约束
1 2 3 4 5 6 7 8 9
| const list :[string,string,number] = ['a','b',11];
const csv :[string,string,number][] = [ ['a','b',11], ['c','d',22], ['e','f',33], ]
|
类定义
1 2 3 4 5 6 7 8 9 10
| class Person { uname : string age : number sayHello(){ return this.content } } const man :Person = new Person() man.uname = 'abc' console.log(man)
|
继承类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Lady extends Person{ sayHello() { return '你好' } sayFF(){ return super.sayHello() } sayF(){ return '交个朋友' } } const goddes = new Xiaojiejie() console.log(goddes.sayF()) console.log(goddes.sayHello())
|
三种访问类型
1 2 3 4 5 6 7 8
| class Person{ public name:string; private age:number; protected sex:string; }
|
构造函数
1 2 3 4 5 6 7
| class Person { public name:string; constructor(name:string){ this.name = name } }
|
构造函数简写
1 2 3
| class Person{ constructor(public name:string){} }
|
继承
1 2 3 4 5 6 7
| class Teacher extends Person { constructor(public age:number){ super('李四') } } const zhangsan = new Person('张三') console.log(zhangsan.name)
|
静态类和实例方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Person { static sayHello(){ return 'hello!' } constructor(private _age:number){} get age(){ return this._age - 10 } set age(age:number){ this._age = age } } console.log(Person.sayHello()) const girl = new Person(88) girl.age = 50 console.log(girl.age)
|
只读属性
1 2 3 4 5 6 7 8 9 10
| class Person { public readonly _name:string; constructor(name:string){ this._name = name } } const ren = new Person('jiuba')
ren._name = 'aa' console.log(ren._name);
|
抽象类
1 2 3 4 5 6 7 8 9 10 11
| abstract class Girl{ abstract skill() }
class Waiter extends Girl{ skill() { console.log('倒水'); } }
|
tsconfig.js
tsc -init
1 2 3
| 'include' : ['demo1.ts',] 'exclude' :['demo2.ts']
|
https://www.tslang.cn/docs/handbook/compiler-options.html
1 2 3 4 5 6 7 8 9 10
| { "compilerOptions": { "removeComments" : true, "strict" : true, "noImplicitAny" : true, "strictNullChecks" : true, "noUnusedLocals" : true, "noUnusedParameters" : true, } }
|
联合类型和类型保护
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| interface Waiter{ anjian : Boolean; say : ()=>{}; } interface Teacher{ anjian : Boolean; skill : ()=>{} }
function judge(agrs:Waiter | Teacher){ if(agrs.anjian){ (agrs as Teacher).skill() }else{ (agrs as Waiter).say() }
if('anjian' in agrs){} if(agrs instanceof Object){} console.log(agrs.anjian); }
|
枚举enum
1 2 3 4 5 6 7 8 9 10 11
| enum bianliang { 'a'= 1, 'b', 'c' } function judge(args:number){ if(args == bianliang['a']){ return args } } console.log(judge(0));
|
泛型
在定义函数和类时,如果遇到类型不明确就可以使用泛型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
function join<ABC>(a:ABC,b:ABC){ return `${a}${b}` } join<string>('a','b')
function Arr<T>(a:Array<T>){ return a } Arr<string>(['abc'])
function demo<T,P>(a:T,b:P){ } demo<string,number>('a',1)
|
在类中使用泛型
不使用泛型的方法
1 2 3 4 5 6 7 8
| class Person{ constructor(private girls:string[]){} getGirl(index:number):string{ return this.girls[index] } } const girls = new Person(['a','b','c']) console.log(girls.getGirl(0));
|
不使用泛型的多类型方法
1 2 3 4 5 6 7 8
| class Person{ constructor(private girls:string[] | number[]){} getGirl(index:number):string | number{ return this.girls[index] } } const girls = new Person(['a','b','c']) console.log(girls.getGirl(0));
|
泛型函数
1 2 3 4 5 6
| function join<T>(a:T):T{ return a; }
join<string>('a')
|
泛型类
1 2 3 4 5 6 7 8 9
| class Person<T>{ constructor(private girls:T[]){} getGirl(index:number):T{ return this.girls[index] } }
const girls = new Person<string>(['a','b','c']) console.log(girls.getGirl(0));
|
泛型接口
1 2 3 4 5 6 7 8 9 10 11
| interface GenericInterface<T> { value: T; getValue(): T; } let stringGenericInterface: GenericInterface<string> = { value: "hello", getValue() { return this.value; } }; console.log(stringGenericInterface.getValue());
|
泛型中的继承
1 2 3 4 5 6 7 8 9 10 11
| interface Girl{ name : string } class Person<T extends Girl>{ constructor(private girls:T[]){} getGirl(index:number) : string{ return this.girls[index].name } } const girls = new Person([{name:'a'},{name:'b'},{name:'c'},]) console.log(girls.getGirl(0));
|
泛型的约束 二选一
约束泛型的类型是string或者number
1 2 3 4 5 6 7 8
| class Person<T extends string | number>{ constructor(private girls:T[]){} getGirl(index:number):T{ return this.girls[index] } } const girls = new Person(['a','b','c']) console.log(girls.getGirl(0));
|
泛型T必须是Inter的实现类(子类)
1 2 3 4 5 6 7 8
| function fn3<T extends Inter>(a:T):nubmer{ return a.length; } interface Inter{ length:number; }
fn3<string>('a')
|
命令空间namespace
1 2 3 4
| npm init -y
tsc -init
|
命名空间
一个ts文件中可以有多个命名空间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| namespace Home{ class Header{ constructor(){ const ele = document.createElement('div') ele.innerText = 'header' document.body.appendChild(ele) } } export class Page { constructor(){ new Header(); } } }
namespace Components { export namespace SubComponents{ export class test{} } export class Header{ constructor(){ const ele = document.createElement('div') ele.innerText = 'header' document.body.appendChild(ele) } } }
|
在其他ts文件中引用
1
| <reference path="Namespace1.ts" />
|
此处会打包出多个js文件需要在tsconfig.js中配置后 打包到一个文件中
1 2 3 4
| { "module":"amd", "outFile":"./build/page.js" }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
import { Header } from './components.js' export default class Page { constructor(){ new Header(); } }
export class Header{ constructor(){ const ele = document.createElement('div') ele.innerText = 'header' document.body.appendChild(ele) } }
request(['page'],function(){ new pageXOffset.default(); })
|
parcel打包ts
用parcle打包ts代码
1 2
| yarn add --dev parcle@next npm install parcle
|
index.html直接引用ts 可以编译
1
| <script src='./page.ts'></script>
|
//package.json
1 2 3 4 5 6
| "scripts":{ "test":"parcel ./src/index.html" } "devDependencies":{ "parcel":"^2.0.0-beta.1" }
|