1.安装方式
安装前提:必须安装NodeJS
全局安装typescript。命令:npm install typescript -g
typescript是以ES3为目标的,但是浏览器基本上都支持es2015(es6)
2.Ts编译为js
2.1在命令台执行tsc hello.ts,执行完后会生成一个hello.js的文件,会出现函数重复的提示。
function greet(person:String,date:Date){
console.log(`Hello ${person},today is ${date}`)
}
greet('calm',new Date())
2.2解决ts和js冲突问题
tsc --init //生成配置文件
2.3 自动编译
tsc --watch
2.4 发出错误(加入ts出现错误不让编译为js文件)
tsc --noEmitOnError hello.ts
3.ts的严格模式配置
"strict": true,//这个包含所有
"noImplicitAny": true,//any类型判断 单独判断
"scriptNullChecks":true //null和undefined的校验 单独判断
"target":"es5"//语言环境
4.typescript的常用类型
:+type 称为类型注释 :string :number :boolean
1.string 定义方法:let str:string = 'hello'
2.number 定义方法:let num:number = 0
3.boolean 定义方法:let bool:boolean = true
4.array 定义方法 type[] Array 其中type为任意类型
eg: let arr:number[] = [1,2,3] let arr2:Array = ['a','b','c']
5.any 任何类型(不希望某个特定值导致类型检查错误)
6.function 函数类型
function greet(name:string):void{
//:string 参数类型注释 :void 返回值类型注释
console.log('hello'+name)
}
const names = ['张三','李四','王五']
names.forEach((s)=>{
//此时的S不需要类型注释,根据数组默认被推断为是strin类型
//整个过程称为上下文类型 因为函数发生在其中上下文通知他应该具有什么类型的上面
console.log(s.toUpperLowerCase())
})
7.object 对象类型
function printCoord(pt:{x:number,y:number}){
//:{x:number,y:number} :{x:number;y:number} {}内可以用,或者;来分隔 参数的类型注释为对象类型
console.log('pt的X坐标':pt.x)
console.log('pt的Y坐标':pt.y)
}
printCoord({x:3,y:7})
function printName(obj:{name:string,age?:number}){
//?:number类型 表示当前被修饰的变量值可有可无
console.log(obj.age.toUpperLowerCase()) //会报错因为age可能为undefined
console.log(obj.age?.toUpperLowerCase()) //正确的写法
}
printName({name:'zhangsan'}) //不会报错因为age可传可不传
union 联合类型
联合类型是指由两个或者多个类型组成的类型,可能是这些类型中的任意一个值。:number | string
function printId(id:number | string){
console.log(id)
if(typeof id === 'string'){
console.log(id.toLowerCase(),'')
}
}
printId(101)
printId('123')
function welcomePeople(x:string[] | string){
if(Array.isArray(x)){
//数组
}
}
welcomePeople('a')
welcomePeople(['a','b'])
function getFirstThree(x:number[] | string):number[] | string{
return x.slice(0,3)
}
getFirstThree('abcdefg') // abc
getFirstThree([0,1,2,3,4]) // [0,1,2]
8.类型别名type
当前项目是不允许两个对象或者函数重名。
定义对象类型:type point = {
x:number,
y:number
}
function printCode(pt:point){}
printCode({
x:100,
y:200
})
定义联合类型 :type ID = string | number
function printTpyeId(id:ID){}
定义基元类型: type Str = string
function printStr(st:Str):Str{}
9.接口interface
interface point {
x:number,
y:number
}
function printCode(pt:point){
}
printCode({
x:100,
y:200
})
10.type和interface的区别(所有通过interface来定义的都可以通过type实现)
1.type和interface的相同点:都是用来定义对象或函数的形状。
2.它俩也支持继承,并且可以互相继承。但是具体的形式稍有差别。
interface是通过extends实现的,type是通过&实现的。
3.type和interface的不同点
type可以定义 基本类型的别名,如 type myString = string
type可以通过 typeof 操作符来定义,如 type myType = typeof someObj
type可以申明 联合类型,如 type unionType = myType1 | myType2
type可以申明 元组类型,如 type yuanzu = [myType1, myType2]
interface可以 声明合并, 这种情况下,如果是type的话,就会报 重复定义 的警告,因此是无法实现 声明合并的
interface Animal {
name:string
}
//扩展方法
interface Bear extends Animal {
honey:boolean
}
const bear:Bear = {
name:"winne",
honey:true
}
console.log(bear.name)//winne
console.log(bear.honey)//true
向现有的类型添加字段
interface Mywindow {
title:string
}
interface Mywindow {
code:number
}
//inteface同时定义两个相同的名称的接口 可以实现合并的来添加新的字段
const w:Mywindow = {
title:"www',
number:'445'
}
type Animal = {
name:string
}
type Bear = Animal & {
honey:boolean
}
const bear:Bear = {
name:"winne",
honey:true
}
向现有的类型添加字段
type Mywindow = {
title:string
}
//这个会报错 因为type类型创建以后是不能更改的
type Mywindow = {
code:number
}
//type扩展的字段的方法&
11.类型断言
const myCanvas = document.getElementById('can_content') as HTMLCanvasElement
const myCanvas2 = <HTMLCanvasElement>document.getElementById('can_content')
const x = 'hello' as number //这样会报错 因为hello被默认获取到的类型是string
const x = ('hello' as any / unknown) as number //any会覆盖number unknown不知道什么类型
12.文字类型
let testString = 'hw'
testString = 'ohw'
const constant = 'how'
let x:'hello' = 'hello' //此时的x不可以在被更改为其它值,只能是hello,相当于用const定义。
function printText(s:string,alignment:'left' | 'right' | 'center'){
}
printText('hello','left')
//数字文字类型
function compare(a:string,b:string):-1|0|1{
return a === b ? 0 : a > b ? 1 : -1
}
compare()
interface Options {
width:number
}
funtion configOption(x:Options | 'auto'){}
//调用configOption 可以传入Options对象也可以传入'auto'
configOption({
width:100
})
configOption('auto')
//布尔文字类型
let b1:true = true
let b2:false = false
function handleRequest(url:string,method:'GET' | 'POST' ){}
const req = {
url:'http://www.baidu.com',
method:'GET'
}
handleRequest(req.url,req.method)
//此时的req.method会报红 是因为method定义的是具体的两种类型,
但是req.method只能推断为string类型,所以就不符合'GET'和'POST'两种文本类型的条件
处理方法就是将req对象的method as 为 'GET'就可以了。
方法一:const req = {
url:'http://www.baidu.com',
method:'GET' as 'GET' //推断为文字类型GET
}
handleRequest(req.url,req.method)
方法二:const req = {
url:'http://www.baidu.com',
method:'GET'
}
handleRequest(req.url,req.method as 'GET')
方法三:将req统一的定为文字类型或者const
const req = {
url:'http://www.baidu.com',
method:'GET'
} as const
handleRequest(req.url,req.method)
13.null和undefined
null 表示不存在
undefined 表示未初始化的值
let x:undefined = undefined
let y:null = null
function doSth(x:string | null){
if(x === null){}else {}
}
function eg2(x?:number | null){
console.log(x!.toFixed()) //x! 就表示x不等于null或者undefined的情况下执行
}
14.枚举
enum Diretion {
Up = 1,
Down,
Left,
Right
}
//设置Up为1 后面的以此类推 就是 2 3 4
console.log(Diretion.Up) //1
console.log(Diretion.Down) //2
15.bigInt 和 symbol
bitInt //非常大的整数
symbol //全局唯一的引用
const oneH:bigint = BigInt(100)
const anH:bigint = 100n //只支持es2020
const firstS = Symbol("name")
const secondS = Symbol("name")
firstS != secondS 因为两个值没有重叠
5.类型缩小
1.类型守卫
function padLeft(padding:number | string,input:string){
//typeof 类型守卫
if(typeof padding === 'number'){
return new Array(padding + 1).join(" ") + input;
}else {
return padding + input;
}
}
typeof strs === 'object' | 'string' | 'number' | 'boolean' | 'bigint' | 'symbol' | 'undefined' | 'function'
function printAll(strs:string | string[] | null){
if(typeof strs === 'object'){
//如果是null也会进这里,因为typeof null === 'object'
//可以实现数组相关的
}else if(typeof strs === 'string'){
//字符串相关
}else {
//null相关
}
}
2.真值缩小
function testN (n:number){
if(n){
return `${n}人在线`
}
return '没人在线'
}
function printAll(strs:string | string[] | null){
if(strs && typeof strs === 'object'){
//可以实现数组相关的
}else if(typeof strs === 'string'){
//字符串相关
}else {
//null相关
}
}
function multiplyAll(values:number[] | undefined,factors:number){
if(!values){
retuen values
}else {
return values.map((v)=>{
return v * factors
})
}
}
multiplyAll([2,3],3) // [6,9]
3.等值缩小
function eg(x:string | number,y:string | boolean){
if(x === y){
//进这里代表类型相等 可以进项字符串相关操作
}else {
}
}
interface contianer {
value : number | null | undefined
}
function mulValue(con:contianer,fac:number){
if(con.value != null){
//con.value != null 此处的条件 也会判断不等于undefined
}
}
mulValue({value:5},6)
mulValue({value:undefined},6)
mulValue({value:null},6)
4.in操作符缩小
type Fish = {
swim:() => void
}
type Bird = {
fly:() => void
}
type human = {
swim?:() => void
fly?:() => void
}
function move(Animal:Fish | Bird | human){
if('swim' in Animal){
//代表就是使用Fish 或 human
return (Animal as Fish).swim()
}
return Animal.fly()
}
5.instanceof操作符缩小
x instanceof Foo
来检查x的原型链上是否含有Foo.prototype
function logValue(x:Date | string){
if(x instanceof Date){
//代表x就是Date的实例
}else {
//字符串
}
}
logValue(new Date())
logValue('asd')
6.分配缩小
let x = Math.Random() < 0.5 ? 10 : 'hw!' //可以看出x是联合类型 let x:string | number
7.控制流分析
function example(){
let x:string | number | boolean
x = Math.Random < 0.5 //此时的x的类型为boolean
if(Math.Random < 0.5){
x = 'lee' //此时的x的类型为string
}else {
x = 100 //此时的x的类型为number
}
return x
}
let x = example()
x = 'hee'
x = 1000
x= false //这里会报错 因为example 函数里面x的boolean类型会被覆盖
8.使用类型谓词
type Fish = {
name:string,
swim:() => void
}
type Bird = {
name:string,
fly:() => void
}
//isFish函数的作用是判断传入的是否是Fish类型
function isFish(pet:Fish | Bird):pet is Fish{
//pet is Fish 称为类型谓词 格式就是函数的形参名 is 类型名称
return (pet as Fish).swim !== undefined
//(pet as Fish).swim !== undefined 条件成立则这个返回值就是Fish不成立则返回值就是Bird
//pet如果有swim这个类型 那么pet就是Fish
}
function getSmallPet():Fish | Bird {
let fish:Fish = {
name:'sharkey',
swim:()=>{}
}
let bird:Bird = {
name:'sparrow',
fly:()=>{}
}
return 'fly' in Bird ? bird : fish
}
let pet = getSmallPet()
if(isFish(pet)){
pet.swim()
}else {
pet.fly()
}
const zoo:(Fish | Bird)[] = [getSmallPet(),getSmallPet(),getSmallPet(),getSmallPet()]
const underWater:Fish[] = zoo.filter(isFish) | zoo.filter(isFish) as Fish[]
const underWater3:Fish[] = zoo.filter((pet):pet is Fish=>{
if(pet.name === 'frog'){
return false
}
return isFish(pet)
})
9.受歧视的unions
interface Shape {
kind:'circle' | 'square';
radius?:number;
sideLength?:number;
}
function handleShape(shape:Shape){
if(shape.kind === 'square'){
}
}
function getArea(shape:Shape){
if(shape.kind === 'circle'){
return Math.PI * shape.radius ** 2
}else {
}
}
function getArea(shape:Shape){
swtich(shape.kind)
case 'circle':
return Math.PI * shape.radius ** 2
case 'square':
return shape.sideLength ** 2
}
10.nerver类型与穷尽性检查
never类型可以分配给任何类型 但是没有类型可以分配给never
interface Circle {
kind:'circle';
radius:number;
}
interface Square {
kind:'square';
sideLength:number;
}
type Shape = Circle | Square
function getArea(shape:Shape){
swtich(shape.kind)
case 'circle':
return Math.PI * shape.radius ** 2
case 'square':
return shape.sideLength ** 2
default:
//在这里既不是圆形也不是方形的情况下 需要一个默认的default never类型
const temp:never = shape
return temp
}
//假如再加一个类型
interface Triangle {
kind:'triangle';
sideLength:number;
}
type Shape = Circle | Square | Triangle
//这种情况函数里的default 的never类型和会报错 是因为此时的default是Triangle类型是存在的
6.函数
1.函数类型表达式
type greatFunction = (a:string) => void
function greater(fn:greatFunction){
fn('hw')
}
function printG(s:string){
console.log(s)
}
greater(printG)
2.调用签名
type DescriableFunction = {
descrition:string;
(someArg:number):boolean;//这里的参数列表和返回类型之间用的是:而不是=>
}
function dosome(fn:DescriableFunction){
console.log(fn.descrition+'111'+fn(6))
}
function fn1(n:number){
console.log(n)
return true
}
fn1.descrition = 'hello'
dosome(fn1) //6 hello 111 true
3.构造签名
class Ctor {
s:string,
constructor(s:string){
this.s = s
}
}
type someConstructor = {
new (s:string):Ctor
}
function fn(ctor:someConstructor){
return new ctor('hello')
}
const f = fn(Ctor)
console.log(f.s) //hello
interface CallorConstructor {
new (s:string): Date
(n?:number):number
}
functino fn1(date:CallorConstructor){
let d = new date('2022-12-12')
let n = date(100)
}
4.泛型函数
function firstElement<Type>(arr:Type[]):Type | undefined{
return arr[0]
}
firstElement<string>(['a','b','c']) // <string> 可写可不写 会推断 返回类型为string
firstElement<number>([1,2,3]) // <number> 可写可不写 会推断 一般不用写
firstElement<undefined>([]) // <undefined> 可写可不写 会推断 一般不用写
//泛型的名字可以任意取
//这个函数需要两个参数,函数的返回值是Output
第一个参数是数组arr,
第二个参数是个函数 函数的返回值是Output,函数的参数是arg Input
function map<Input,Output>(arr:Input[],func:(arg:Input)=>Output):Output[]{
return arr.map(func)
}
const parst = map(['1','2','3'],(n) => parseInt(n))
//根据传参可以推断出input是string Output是number
function longest<Type>(a:Type,b:Type){
if(a.length >= b.length){
return a
}else {
return b
}
}
//Type 上面的写法在调用a.length||b.length的时候会出现没有length属性的可能,
需要在泛型Type后面extends一下
function longest<Type extends {length:Number}>(a:Type,b:Type){
if(a.length >= b.length){
return a
}else {
return b
}
}
const longArray = longest([1,2],[2,3,4]) //Type就是number
const longArray = longest('aaa','bbbb') //Type就是string
function mininumlength<Type extends {length:Number}>(obj:Type,mininum:number):Type{
if(obj.length >= mininum){
return obj
}else {
return {length:mininum}
}
}
const arr = mininumlength([2,3,4],6)
//如果条件成立则可以
function combine<Type>(arr1:Type[],arr2:Type[]):Type[]{
return arr1.concat(arr2)
}
const arr = combine([1,2,3],[5,6,7])
const arr = combine([1,2,3],['a','b'])//会报错因为第一个参数已经推断出arr是数字类型数组
const arr = combine<number | string>([1,2,3],['a','b'])//正常运行 不报错
1.可能情况下,使用类型参数本身,而不是对其进行约束。
function firstElement1<Type>(arr:Type[]){
return arr[0]
}
function firstElement2<Type extends any[]>(arr:Type){
return arr[0]
}
一般写法选择firstElement1
const a = firstElement1([1,2,3])
const b = firstElement2([1,2,3])
2.总是尽可能少的使用类型参数。
function filter1<Type>(arr:Type[],func:(arg:Type)=>boolean){
return arr.filter(func)
}
function filter2<Type,Func extends (arg:Type)=>boolean>(arr:Type[],func:Func){
return arr.filter(func)
}
//一般使用第一种方式 不需要单独定义类型参数
3.如果一个类型参数只出现在一个地方,请重新考虑你是否真的需要它。
function greet<Str extends string>(s:Str){
consoloe.log('hello'+s)
}
greet('word')
function greet2(s:string){
consoloe.log('hello'+s)
}
greet2('word')
5.函数的可选参数
function f(n:number){
console.log(f.toFixed())
console.log(f.toFixed(3))
}
f(123.45)
//123
//123.450
f()//直接调用不传参数
function f(n:number = 100){
console.log(f.toFixed())
console.log(f.toFixed(3))
}
function f(n?:number){
console.log(f!.toFixed())
console.log(f!.toFixed(3))
}
6.回调函数的可选参数
function myforeach(arr:any[],callback:(arg:any,index?:number)=>void){
for(lei i = 0;i < arr.length;i++){
callback(arr[i],i)
}
}
myforeach([1,2,3],(item,index)=>{
console.log(item,"ppp")
})
7.函数重载
//重复定义的函数称为函数签名
function makeDate(timestamp:number):Date
function makeDate(m:number,d:number,y:number):Date
function makeDate(mortimestamp,d?:number,y?:number):Date{
if( d !== undefined && y !== undefined){
return new Date(y,mortimestamp,d)
}else {
return new Date(mortimestamp)
}
}
//前两个函数称为重载签名
//第三个函数称为实现签名
const d1 = makeDate(123123213132)
const d2 = makeDate(5,6,7)
const d3 = makeDate(6,7) //这里会报错,因为函数参数的个数取决于重载签名函数的参数
function fn(x:string):void
function fn(){
}
fn('hello')//此处调用必须传参,因为函数参数的个数取决于重载签名函数的参数
//重载签名
function fn1(x:boolean):void
function fn1(x:string):void
//实现签名
function fn1(x:booloan | string){
}
//返回值类型也需要包含重载签名函数的返回值
function fn2(x:string):string
function fn2(x:boolean):boolean
function fn2(x:string | boolean):string | boolean{
}
函数重载准则:
1.在可能的情况下,总是倾向于使用联合类型的参数而不是重载参数
function len(s:string):number
function len(arr:any[]):number
function len(x:any){
return x.length
}
len('wewewe')
len(['1','3'])
len(Math.random() > 0.5 ? 'hello' : [1,2,3]) //这里会报错,因为string | number[] 不能付给string
number[] 不能赋值给string类型 同理 string也不能赋值给any[]类型
//改写
function len(x:any[] | string){
return x.length
}
interface User {
admin:boolean
}
interface DB {
filterUsers(filter:(this:User)=>booloean):User[]
}
const db:DB = {
filterUsers:(filter:(this:User)=>booloean)=>{
let user1:User = {
admin:true
}
let user2:User = {
admin:false
}
return [user1,user2]
}
}
const admins = db.filterUsers(function(this:User){
return this.admin
})
consol.log(admins) //返回这个数组[{admin:true},{admin:false}]
8.需要了解的其他类型
1.void
当一个函数没有任何返回语句,或者没有从这个返回语句中返回任何明确的值的时候,它都是推断出来void
eg:function noop(){
return; //推断返回的是void
}
在javascript中一个不反悔任何值的函数,将隐含的返回undefined这个值
在typescript中void和undefined是不一样的
2.object
object指的是任何的不是基元的值:!(string number booloean bigint symbol null undefined)
小写的object不等同与{},也不等同于Object
在javascript函数值是对象,它们有属性,比如它们的原型链里面有Object.prototype,
是大写的Object一个实例,可以对它调用Object.key等等
object不是Object,在ts中始终使用object
3.unknown
unknown类型代表任何值。这与any类型类似,但更安全,因为对未知的unknown值做任何事情都是不合法的。
eg: function f1(a:any){
a.b() //不会报错
}
function f2(a:unknown){
a.b() //报错
}
function f3(s:string):unknown{
return JSON.Parse(s)
}
const obj = f3(aaa)
4.never
never类型表示永远不会被观察到的值
eg:function f(msg:string):never{
return new Error(msg);
}
如果一个函数抛出异常,或者中止程序的执行,或者是死循环,那么它的返回值就是never
function f6(x:string | number){
if(typeof x === 'string'){
}else if(typeof x === 'number'){
}else {
x //never
}
}
5.Function
全局性的Function类型描述了诸如bind,call、apply和其他存在于Javascript中所有函数值的属性。它
还有一个特殊的属性,即Function类型的值总是可以被调用,这些调用返回any。
function f5(f:Function){
return f(1,2,3)
}
如果需要接受一个任意函数但是不打算调用最好使用()=>void这种方法
9.参数展开运算符
function f1 (n:number,...m:number[]){
return m.map(x => n * x )
}
const a = f1(10,1,2,3,4)
//此时的a就是 [10,20,30,40]
const arr1 = [ 1,2,3]
arr1.push(4,5,6)
//arr1 [1,2,3,4,5,6]
const arr2 = [4,5,6]
arr1.push(...arr2)
//arr1 [1,2,3,4,5,6]
const args = [8,5] as const
const angle = Math.atan2(...args)
10.参数结构
function sum({a,b,c}:{a:number,b:number,c:number}){
//不定义类型会下划线提示报错
console.log(a+b+c)
}
sum({a:1,
b:3,
c:5
})
type ABC = {a:number,b:number,c:number}
function sum({a,b,c}:ABC){
//不定义类型会下划线提示报错
console.log(a+b+c)
}
11.返回void类型
一个具有void返回类型的上下文函数类型(type vf=()=>void),在实现时,可以返回任何其它的值,但它会被忽略。
当一个字面的函数,定义有一个void的返回类型时,该函数必须不返回任何东西。
type voidFunc = () => void
const f1:voidFunc = () => {
return true
}
const f2:voidFunc = () => true
const f3:voidFunc = function(){
return true
}
const v1:booloean = f1() //此处会出错 是因为上面的类型已经规定的函数的返回值是void
const v2 = f2()
const v3 = f3()
function f4() :void{
return true //此时会报错 因为返回值必须是void
}
const f5 = function() :void{
return true //此时会报错 因为返回值必须是void
}
7.对象类型
匿名对象
function greet(person:{name:string,age:number}){
return 'hello' + progress.name
}
接口命名
interface Person {
name:string,
age:number
}
function greet(person:Person){
return 'hello' + progress.name
}
类型别名
type Person = {
name:string,
age:number
}
function greet(person:Person){
return 'hello' + progress.name
}
可选属性
type Shape = {}
interface PaintOptions{
shape:Shape,
xPos?:number,
yPos?:number
}
function paintShape(opts:PaintOptions){
let xpos = opts.xPos
let ypos = opts.yPos
}
const shape:Shape = {}
paintShape({shape})
paintShape({shape,xPos:100})
function paintShape({shape:Shape,xPos:number=100,yPos=200}:PaintOptions){
//shape:Shape,xPos:number=100,yPos=200 属性别名
console.log(number)//此时的number是0
}
只读属性
interface SomeType {
readonly prop:string
}
function dsth(obj:SomeType){
console.log(obj.prop)
obj.prop = '' //这里会报错只读类型不可被修改
}
interface Home {
readonly resident:{
name:string,
age:number
}
}
function name(home:Home){
Home.resident = {} //这里会报错只读类型不可被修改
但是Home.residentd.age++ 可以修改,只约束了外层对象,不可约束里
如果给residentd的age添加readonly属性 则residentd.age也就不可修改
}
readonly的属性可以通过别名改变
interface Person {
name:string,
age:nunmber
}
interface ReadOnlyPerson {
readonly name:string,
readonly age:nunmber
}
let writablePerson:Person = {
name:'calm',
age:18
}
let readonlyPerson:ReadOnlyPerson = writablePerson
//此时没有报错,只读属性可以用可写属性赋值
console.log(readonlyPerson.age)
writablePerson.age++
console.log(readonlyPerson.age)
此时会发现年龄加了一岁
索引签名
interace StringArray {
[index:number]:string
}
const myArray:StringArray = ['a','b'] 值的类型必须和定义的一样为string
const secondItem = myArray[0]
console.log(secondItem,"secondItem")
interface TestString {
[props:string]:number
}
const testString:TestString = {
x:100,
y:200 值的类型必须和定义的一样为Number
}
interface Animal {
name:string
}
interface Dog extends Animal {
breed:string
}
interface NotOk {
[index:string]:number | string,
length:number,
name:string //这里会报错因为类型string 不一颗赋给number 在上面声明联合类型就可以
}
let notOk:NotOk = {
x:100,
length:10,
name:'ddd'
}
interface ReadOnlyStringArray {
readonly [index:number]:string,
}
let myArray:ReadOnlyStringArray = ['a','b']
myArray[0] = 'fff' //这里会报错,因为只读属性不能被修改
扩展类型
interface BasicAddress {
name?:string,
street:string,
city:string,
country:string,
postCode:string
}
interface AddressWithUnit extends BasicAddress {
unit:string
} //这样AddressWithUnit就具有了所有属性
let awu:AddressWithUnit = {
unit:3,
street:'中华街道',
city:'bj',
post:'100100',
country:'china',
name:'222'
}
interface Colorful {
color:string
}
interface Circle {
radius:number
}
interface ColorCircle extends Colorful,Circle {
}
const cc:ColorCircle = {
color:'red',
radiud:100
}
交叉类型
interface Colorful {
color:string
}
interface Circle {
radius:number
}
//定义交叉类型
type ColorCircle = Colorful & Circle; //& 可以实现类型联合
let cc:ColorCircle = {
color:'red',
radius:200
}
//
function draw(circle:Colorful & Circle){
consoloe.log(circle.color)
consoloe.log(circle.radius)
}
draw({
color:'red',
radius:100
})
接口和交叉类型的区别
接口可以使用extends
交叉类型可以用type的&连接
interface sister {
name:string
}
interface sister {
age:number
}
定义同名接口的会合并
const s:sister = {
name:'demon',
age:34
}
类型别名type不可定义两个相同名称的别名
泛型对象类型
interface Box {
contents:any
}
let box:Box = {
contents:'hh'
}
interface Box {
contents:unknown
}
let x:Box = {
contents:'hh'
}
console.log(x.contents.toLowerCase())//会报错 因为是unknown类型
解决方法:
if(type of x.contents === string){
console.log(x.contents.toLowerCase())
}
console.log((x.contents as string).toLowerCase())
//函数重载
interface numberBox {
contents:number
}
interface stringBox {
contents:string
}
interface booleanBox {
content:boolean
}
function setContents(box:stringBox,newContents:string):void
function setContents(box:numberBox,newContents:number):void
function setContents(box:booleanBox,newContents:boolean):void
function setContents(box:{contents:string | number | boolean},newContents:any):void{
box.contents = newContents
}
//优雅的泛型来定义
interface Box<Type> {
contents:Type
}
let boxA:Box<string> = {
contents:'hh'
}
let boxA:Box<number> = {
contents:100
}
//
interface Box<Type> {
contents:Type
}
interface Apple {
}
let a:Apple = {}
type AppleBox = Box<Apple>
let ab:AppleBox = {
contents:a
}
//通过type定义泛型对象类型
type Box<Type> = {
contents:Type
}
type orNull<Type> = Type | null
type OneOrMany<Type> = Type | Type[]
type OneOrManyOrNull<Type> = orNull<OneOrMany<Type>>
type OneOrManyOrNullOrString<Type> = OneOrManyOrNull<string>
数组类型(泛型)
1.类型操纵
用现有类型或者值来表达新的类型的方法
泛型类型:带有参数的类型
keyof:用keyof创建新类型
typeof:用typeof新类型
索引访问类型:Type['a']这种语法可以访问类型的子集
条件类型:可以在类型系统中类似if创建类型
映射类型:映射现有类型中的每个属性来创建类型
模板字面量类型:通过模板字面量的字符串来改变属性的映射类型
2.什么是泛型
function identity<Type>(arg:Type):Type {
return arg
}
let output:identity<string>('mystring')
let output:identity('mystring')
3.使用通用类型
function loggingIdentity<Type>(arg:Array<Type>):Type[] {
console.log(arg.length)
return arg
}
loggingIdentity('hello')
4.泛型类型
function identity<Type>(arg:Type):Type {
return arg
}
let myIdentity:<Type>(arg:Type)=>Type = identity
let myIdentity:{<Type>(arg:Type):Type} = identity
//泛型接口
interface GenericIndeentityFn{
<Type>(arg:Type):Type
}
let myIdentity:GenericIndeentityFn = identity
//泛型接口定义
interface GenericIndeentityFn<Type>{
(arg:Type):Type
}
let myIdentity:GenericIndeentityFn<string> = identity
5.泛型类
class GenericNumber<NumType> {
zeroValue:NumType,
add:(x:NumType,y:NumType)=>NumType
}
//number
let myGeneric = new GenericNumber<number>()
myGeneric.zeroValue = 0
myGeneric.add() = function (x,y){
return x + y
}
//string
let myGeneric = new GenericNumber<number>()
myGeneric.zeroValue = 'hello'
myGeneric.add() = function (x,y){
return x + y
}
6.泛型约束
interface lengthWise {
length:number
}
//Type extends lengthWise 用户传入必须带有Length
function loggingIndetity<Type extends lengthWise>(arg:Type):Type{
return arg
}
loggingIndetity(['hello','word'])
loggingIndetity('hello')
7.在泛型约束中使用类型参数
//key必须在type中存在
function getProperty<Type,Key extends keyof Type>(obj:Type,key:Key){
return obj[key]
}
let x = {
a:1,
b:2,
c:3,
d:4
}
getProperty(x,'a')
getProperty(x,'m')//这里会报错 x中不存在m