01
typescript的操縱類型
//從類型中創(chuàng)建類型:泛型類型、keyof類型操作符、typeof操作類型符、索引訪問類型、條件類型、映射類型、模板字面量類型
//我們通過模板字面量的字符串來改變屬性的映射類型
//軟件工程的一個主要部分是建立組件,這些組件不僅有定義明確和一致的api,而且還可以重復(fù)使用,能夠處理今天的數(shù)據(jù)和明天的數(shù)據(jù),這些組件將為我們建立大型軟件系統(tǒng)提供最靈活的能力,比如像c#和java這樣的語言中,創(chuàng)建可重用組件的工具箱中有一個非常重要的工具,就是泛型。也就是說能夠創(chuàng)建一個在各種類型上工作的組件,而不是單一的類型,這就使得用戶可以消費(fèi)這些組件,并且使用自己的類型。
/**例如:
function identity<type>(arg:Type):Type{
return arg;
}
*/
//在函數(shù)名后添加一個Type的類型,這個Type允許我們捕獲用戶提供的類型,比如number,string,這樣我們就可以在以后使用這些信息了,這里我們再次使用Type作為返回值,經(jīng)過檢查,我們看到參數(shù)的類型和返回的類型使用的是相同的type這個類型,這就使得我們可以講類型信息從函數(shù)的一側(cè)輸入,然后從另一側(cè)輸出。我們說這個版本的函數(shù)是通用的,因?yàn)樗谝幌盗械念愋蜕厦婀ぷ骱臀覀兪褂胊ny類型不同的是,它和我們第一次使用的number這個參數(shù)和返回number類型的identity,它的作用是一樣的精確,也就是說它不會丟失任何的類型信息。寫好通用函數(shù),我們就可以使用兩種方式來調(diào)用它了.
//第1種方式:我們將所有的參數(shù)包括類型參數(shù)都傳遞給函數(shù),如
/**
function identity<Type>(arg:Type):Type{
return arg
}
let output=identity<string>("myString")//方式1
let output=identity("myString")//方式2
*/
//我們看在identify調(diào)動的時候加上一個<>定義泛型類型,這里寫了<string>然后在()里傳入實(shí)參
//第2種方式:使用類型參數(shù)推斷,也就是說我們希望編譯器根據(jù)我們傳入的參數(shù)的類型,自動為我們設(shè)置這開發(fā)的值的類型,我們把string去掉
//使用通用類型
function loggingIdentify<Type>(arg: Type): Type {
//console.log(arg.length);//報錯,泛型類型Type上不存在length。但實(shí)際上是可以獲取length的,但ts語法上不允許這樣表達(dá)
return arg;
}
//如果用戶傳入數(shù)組可以求值length,但是如果用戶傳入number那就獲取不到length了,那就會產(chǎn)生問題,要傳入數(shù)組,應(yīng)如下改造:
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
}
//定義泛型函數(shù)的形式:()=>
//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
在泛型約束中使用類型參數(shù)
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 {
//定義一個屬性,實(shí)例類
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"聯(lián)合類型
//索引簽名
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類型
//預(yù)定義類型
//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的后邊去調(diào)用這個函數(shù)試圖去返回函數(shù)的返回結(jié)果的類型,這是由問題的。也就是說tyof只能是去修飾一個變量或者某個對象里的屬性,不能修飾函數(shù)體類型
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這個屬性不可用的情況下,把它默認(rèn)為返回一個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
在條件類型內(nèi)進(jìn)行推斷
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 = []
//非分發(fā)式的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
}
}