01
typescript的操纵类型
//从类型中创建类型:泛型类型、keyof类型操作符、typeof操作类型符、索引访问类型、条件类型、映射类型、模板字面量类型
//我们通过模板字面量的字符串来改变属性的映射类型
//软件工程的一个主要部分是建立组件,这些组件不仅有定义明确和一致的api,而且还可以重复使用,能够处理今天的数据和明天的数据,这些组件将为我们建立大型软件系统提供最灵活的能力,比如像c#和java这样的语言中,创建可重用组件的工具箱中有一个非常重要的工具,就是泛型。也就是说能够创建一个在各种类型上工作的组件,而不是单一的类型,这就使得用户可以消费这些组件,并且使用自己的类型。
/**例如:
function identity<type>(arg:Type):Type{
return arg;
}
*/
//在函数名后添加一个Type的类型,这个Type允许我们捕获用户提供的类型,比如number,string,这样我们就可以在以后使用这些信息了,这里我们再次使用Type作为返回值,经过检查,我们看到参数的类型和返回的类型使用的是相同的type这个类型,这就使得我们可以讲类型信息从函数的一侧输入,然后从另一侧输出。我们说这个版本的函数是通用的,因为他在一系列的类型上面工作和我们使用any类型不同的是,它和我们第一次使用的number这个参数和返回number类型的identity,它的作用是一样的精确,也就是说它不会丢失任何的类型信息。写好通用函数,我们就可以使用两种方式来调用它了.
//第1种方式:我们将所有的参数包括类型参数都传递给函数,如
/**
function identity<Type>(arg:Type):Type{
return arg
}
let output=identity<string>("myString")//方式1
let output=identity("myString")//方式2
*/
//我们看在identify调动的时候加上一个<>定义泛型类型,这里写了<string>然后在()里传入实参
//第2种方式:使用类型参数推断,也就是说我们希望编译器根据我们传入的参数的类型,自动为我们设置这开发的值的类型,我们把string去掉
//使用通用类型
function loggingIdentify<Type>(arg: Type): Type {
//console.log(arg.length);//报错,泛型类型Type上不存在length。但实际上是可以获取length的,但ts语法上不允许这样表达
return arg;
}
//如果用户传入数组可以求值length,但是如果用户传入number那就获取不到length了,那就会产生问题,要传入数组,应如下改造:
function loggingIdentify2<Type>(arg: Array<Type>): Type[] {
console.log(arg.length);
return arg;
}
loggingIdentify2([1,2,3,4])
02
function identify<Type>(arg:Type):Type{
return arg
}
//定义泛型函数的形式:()=>
//let myIdentity:()=>identify
//let myIdentity:(arg:Type)=>identify
let myIdentity:<Type>(arg:Type)=>Type=identify
//写成对象字面量的形式:{}=
//let myIdentity2:{key值}=identify
let myIdentity2:{<Type>(arg:Type):Type}=identify
//将泛型字面量的形式写成泛型接口
interface GenericIdFn{
// ():Type
<Type>(arg:Type):Type
}
let myIdentity3:GenericIdFn=identify
//接口方式的另一个写法,更灵活一些
interface GenericIdFn2<Type>{
(arg:Type):Type
}
let myIdentity4:GenericIdFn2<string>=identify
03
class GenericNumber<NumType>{
zeroValue: NumType
add: (a: NumType, y: NumType) => NumType
}
let myGeneric = new GenericNumber<number>()
myGeneric.zeroValue = 0
myGeneric.add = function (x, y) {
return x + y
}
let myGeneric2 = new GenericNumber<string>()
myGeneric2.zeroValue = ''
myGeneric2.add = function (x, y) {
return x + y
}
04
泛型约束
interface Lengthwise{
length:number
}
function loggingId<Type extends Lengthwise>(arg: Type): Type{
console.log(arg.length);
return arg;
}
loggingId(['hello',2,22])
05
在泛型约束中使用类型参数
function getProperty<Type, Key extends keyof Type>(obj: Type, key: Key) {
return obj[key]
}
let x = {
a: 1,
b: 2,
c: 3
}
getProperty(x, 'a')
06
在泛型中使用类类型
// function creat<Type>(c: { new(): Type }): Type {
// return new c();
// }
class Beekeeper {
hasMask: boolean = true
}
class Zoo {
nametag: string = 'Miki'
}
class Animal {
numLegs: number
}
class Bee extends Animal {
//定义一个属性,实例类
keeper: Beekeeper = new Beekeeper()
}
class Lion extends Animal {
keeper: Zoo = new Zoo()
}
//形参传入一个类,并返回类
function creatInstance<A extends Animal>(c:new()=>A): A {
return new c();
}
creatInstance(Lion).keeper.nametag
creatInstance(Bee).keeper.hasMask
//creatInstance(Beekeeper)//报错,Beekeeper没有继承Animal
07
keyof类型操作符
type Point = { x: number; y: number };
type P = keyof Point;
const p1: P = 'x'
const p2: P = 'y'
//所以type P = keyof Point;的P的类型是 "x"|"y"联合类型
//索引签名
type Arrayish={
[n:number]:unknown
}
type Mapish={
[k:string]:boolean
}
type M=keyof Mapish
const m1:M='sss'
const m2:M=177
// const m3:M=false//报错,不能将类型boolean分配给类型"string|number"
08
typeof
//了解原生的type,console.log(typeof 'helloWorld');
// let s = "hello"
// let n: typeof s
// n = 'helll'
// n = 777 //报错,number不能分派给string类型
//预定义类型
//ReturnType<T>
// type Predicate = (x: unknown) => boolean
// type K = ReturnType<Predicate>
// function f() {
// return {
// x: 99,
// y: 22
// }
// }
// type PP=ReturnType<typeof f>
// const hh:PP={x:3,y:99}
// const p:PP=100//报错:不能将number分配给类型“{x:number,y:number}”
function msg() { }
let shouldC: typeof msg
//shouldC = 100 //报错:不能将类型number分配给类型()=>void
//注意:我们绝对不能在typeof的后边去调用这个函数试图去返回函数的返回结果的类型,这是由问题的。也就是说tyof只能是去修饰一个变量或者某个对象里的属性,不能修饰函数体类型
09
type Person = {
age: number,
name: string,
alive: boolean
}
//通过索引的方式访问Person里面age属性
type Age = Person['age']
let age: Age = 99
//只能访问number类型
type Person2 = {
age: number,
name: string,
alive: boolean
}
type L1 = Person2['age' | 'name']
let L11: L1 = 88
//可以访问number和string两种类型
type L2 = Person2[keyof Person2]
//age、name、alive三种类型都可访问
const MyArray = [
{ name: 'bunny', age: 18 },
{ name: 'heihei', age: 99 }
]
type Person3 = typeof MyArray[number]
let aaa:Person3={
name:'bbb',
age:44
}
//只能在类型使用索引
10
interface Animal {
live(): void
}
interface Dog extends Animal {
woof(): void
}
//type Example1=number
type Example1 = Dog extends Animal ? number : string
//type Example2=string
type Example2 = Dog extends Animal ? number : string
//泛型条件类型
interface IdLabel {
id: number
}
interface NameLabel {
name: string
}
type NameOrId<T extends number | string> = T extends number ? IdLabel : NameLabel
function createLable<T extends number | string>(idOrName: T): NameOrId<T> {
throw ''
}
//type a=NameLable
let a = createLable('typescript')
//tyoe b=IdLabel
let b = createLable(25)
//type c =NameLable | IdLabel
let c = createLable(Math.random() > 0.9 ? 'hello bunny' : 250)
11
//条件类型约束
//type MessageOf<T>=T['message']
type MessageOf<T extends {message:unknown}>=T['message']
interface Email{
message:string
}
type EmailMessageContents =MessageOf<Email>
//如果我们想要MessageOf来接收任何类型,并且在Message这个属性不可用的情况下,把它默认为返回一个never类型,这时候就需要一个约束条件移出再引入另外一个条件类型了
type MessageOf2<T>=T extends {message:unknown}?T['message']:never
interface Email2{
message:string
}
interface Dog{
bark():void
}
type EmailMessageContents2 =MessageOf2<Email2>
const emc:EmailMessageContents2='hvdsjcvcf'
type DogMessageContents = MessageOf2<Dog>
// const dmc:DogMessageContents ='erro' //报错,不能将string分配给类型never ,可以加断言
const dmc:DogMessageContents ='erro' as never
12
在条件类型内进行推断
type GetReturnType<Type>=Type extends (...arg:never[])=>infer Return?Return:number
//type Nmu =number
type Num =GetReturnType<()=>number>
let num:Num =100
//type Nmu =string
type Str = GetReturnType<(x:string)=>string>
let str:Str=''
//type Bools=boolean[]
type Bools=GetReturnType<(a:boolean,b:boolean)=>boolean[]>
let bools:Bools=[false,true]
//type Never=never
type Never = GetReturnType<string>
let never:Never ='error' as never
function sn(x:string):number
function sn(x:number):string
function sn(s:string|number):string|number
function sn(s:string|number):string|number{
return Math.random()>0.5 ? 'hello':23
}
//type T1=Return
type T1=ReturnType<typeof sn>
//const t1:T1=true//报错,不能将boolean分配给string|number
13
分布式条件类型
type ToArray<T> = T extends any ? T[] : never
type SN = ToArray<string | number>
//type SN = string[]|number[]
//type SN = (string|number)[]
//type SN =ToArray<string|number>
let saon: SN = []
//非分发式的ToArray
type TADist<T> = [T] extends [any] ? T[] : never
type SAON = TADist<string|number>
let san1:SAON =['1',22]
//let san:SAON =[true]//报错,不能将类型boolean分配给string|number
tsconfig.json
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"rootDir": "./src",
"outDir": "./dist",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"strictPropertyInitialization": false,
"skipLibCheck": true
}
}
网友评论