數(shù)據(jù)類(lèi)型

typescript

命令

? tsc --init 生成配置文件

{'compilerOptions': {
    'target': 'es5',
    'module': 'commonjs',
    'strictNullChecks': true // 是否嚴(yán)格null檢查,為true,undefined和null不為基礎(chǔ)數(shù)據(jù)類(lèi)型的子集
}}
scripts:{
    'build': 'tsc'
    'start': 'tsc--watch'
}

ts的基礎(chǔ)數(shù)據(jù)類(lèi)型

特殊數(shù)據(jù)類(lèi)型

數(shù)組

1.長(zhǎng)度任意

2.類(lèi)型必須統(tǒng)一

let names:string[] = ['a', 'b', 'c']
let names2: Array<string> = ['a', 'b', 'c'] // 泛型寫(xiě)法

元組

1.長(zhǎng)度和類(lèi)型都確定的數(shù)組

let persong:[string, number, string] = ['zhufeng', 10, 'male']
console.log(person[0].length)
console.log(person[1].tofixed(2))
console.log(person[2].length)

枚舉類(lèi)型

enum Gender {
    BOY,
    GIRL
}
let boy: number = Gende.BOY  // 0

常量枚舉

const enum Colors {
    RED,
    YELLOW,
    BULE
}
let colors= [Colors.RED, Colors.YELLOW, Colors.BULE] // [0,1,2]

Any 任意類(lèi)型

let x:any

never 類(lèi)型

1.作為沒(méi)有返回值的函數(shù)的返回值類(lèi)型

function get():never {
    console.log(1)
    throw new Error('報(bào)錯(cuò)了')
}

never和void的區(qū)別

  • void可以被賦值為null和undefined的類(lèi)型。never則是一個(gè)不包含值的類(lèi)型

  • 擁有void返回值類(lèi)型的函數(shù)能正常運(yùn)行。擁有never返回值類(lèi)型的函數(shù)無(wú)法正常返回,無(wú)法中止,或者拋出異常

包裝類(lèi)

基本數(shù)據(jù)類(lèi)型是沒(méi)有方法的

let name1 = 'zhufeng'
// -----------------------------
new String('zhufeng').toLocleLowweCase()
// -----------------------------
let hasGirl:boolean = true
hasGirl = Boolean(true)
hasGirl = new Boolean(true) // 這里是錯(cuò)誤的,基本數(shù)據(jù)類(lèi)型內(nèi)置已經(jīng)幫我們轉(zhuǎn)了對(duì)象,所以不能用對(duì)象進(jìn)行復(fù)制

當(dāng)你在一個(gè)基本數(shù)據(jù)類(lèi)型上調(diào)用方法時(shí),會(huì)立刻隱含的把一個(gè)基本數(shù)據(jù)類(lèi)型包裝成對(duì)象

聯(lián)合類(lèi)型

let name: string | number
name = 'zhufeng'
name = 10

類(lèi)型斷言

let name: string | number
name = 'zhufeng'
name = 10
(name as tring).length
function getName(val: string|number|boolean) {
    (val as string).length
}

type

// type 用來(lái)定義類(lèi)型別名
// 函數(shù)表達(dá)式
type GetUserName = (x:string, y:string) => string
let getUserName: GetUserName = function(firstName, lastName):string {
    return firstname+lastname
}

// 可選參數(shù) 加上問(wèn)號(hào)
let items:number[] = [1,2,3,4]
type IteratorFun = (item:number, index?:number, arr?:number[]) => void
let iteratorFun:IteratorFun = function(item:number, index:number, arr:number[]) {}
item.forEach(iteratorFun)

// 默認(rèn)參數(shù)
function ajax(url:string, methods:string="GET"){
    
}
ajax('/user')

// 剩余參數(shù)
function sum(prexfix: string, ...args:number[]) {
    return prefix+arg.reduce((val, item) => val+=item,0)
}
let r = sum('$', 1,2,3,4)

// 類(lèi)型的重載
type MyType = string|number|boolean
function getType(val:MyType):MTtype {
    return val
}

// 函數(shù)的重載
function double(val:string): string
function double(val:number): number
function double(val:boolean):boolean 
function double(val:any) {
    if (typeof val === 'string') {
        return val+val
    }
    if (typeof val === 'number') {
        return val*2
    }
    if(typeof val=== 'boolean') {
        return val
    }
}

類(lèi)

// get name
class Person1 {
    myname: string,
    constructor(myname:string){
       this.myname = myname
    }
get name() {
    return this.myname
}
set name(val) {
    this.myname = val
}
}
let p1 = new Person1()
p1.name

參數(shù)的屬性

// 加上public 之后相當(dāng)于給當(dāng)前的實(shí)例增加一個(gè)公有屬性
// public priviate protected
class Person2 {
    constructor(public myname:string){
        
    }
}

// readonly 只讀 參數(shù)不可改
class Person4{
    public readnoly id:number
    constructor(id:number) {
        this.id = id
    }
}

class Parent {
    public name:string; // 公有的name屬性,所有地方都能訪問(wèn)
    protected age:number; //  受有限度的保護(hù)的屬性,只能在自己或自己的子類(lèi)中被訪問(wèn)
    priviate money:number; // 私有屬性,只能自己訪問(wèn),連自己的子類(lèi)都不能訪問(wèn)
    constructor(name:string, age:number, money:number) {
        this.name = name
        this.age = age
        this.money = money
    }
    getName() {
        console.log('a', this.name)
    }
    getAge() {
        console.log('a', this.age)
    }
    getMoney() {
        console.log('a', this.money)
    }

}

class Child extends Parent {
    getName() {
        console.log('b', this.name)
    }
    getAge() {
        console.log('b', this.age)
    }
    getMoney() {
        console.log('b', this.money)
    } // 在這里已經(jīng)報(bào)錯(cuò)不能訪問(wèn)了
}

let c = new Child('zfpx',10,100)
c.getName() // 可以正常訪問(wèn)
c.getAge() // 只能在子類(lèi)中訪問(wèn),這里是實(shí)例
c.getMoney() // 只能在自己中訪問(wèn)

靜態(tài)屬性

// 普通類(lèi)
class Father {
    static myname:string = 'zhufeng'
    static getMyName() {
        return Father.myname
    }
}
console.log(Father.name)
Father.getMyName()

// 抽象類(lèi) abstract
// 抽象類(lèi)是一種抽象的概念,無(wú)法被實(shí)例化,只能被繼承
// 抽象類(lèi)里的方法是抽象的
// 重寫(xiě) 父類(lèi)是一樣 子類(lèi)重寫(xiě)父類(lèi)邏輯 子類(lèi)重寫(xiě)竭誠(chéng)父類(lèi)中的方法
// 重載 同一個(gè)函數(shù)提供多個(gè)類(lèi)型定義
abstract class Animal {
    name:string;
    abstract speak()
}

class Cat extends Animal{
    speak() {
        // 要把抽象類(lèi)的方法執(zhí)行了才不會(huì)報(bào)錯(cuò)
    }
}

繼承vs多態(tài)

  • 繼承 子類(lèi)繼承父類(lèi),子類(lèi)除了擁有父類(lèi)所有的特性外,還有一些更具體的特性
  • 多態(tài) 由繼承而產(chǎn)生了相關(guān)不同的類(lèi),對(duì)同一個(gè)方法可以有不同的響應(yīng)

接口

  • 用來(lái)描述一種對(duì)象解構(gòu)或者對(duì)象的形狀
  • 用來(lái)描述一種抽象的特性集合
interface UserInterface{
    name:string
    age:number
}
let user:UserInterface= {
    name:'zhufeng',
    age:10
}

// 抽象特性集合
interface Flyable{
    fly():void
}
class Bird implements Flyable{
    fly(){
        console.log('小鳥(niǎo)飛')
    }
}

interface Person6 {
    readonly id: number;
    name: string
    [propName:string]:any // [propName] key 表示未知的其它屬性
}
let p3: Person = {
    id: 1,
    name: 'zhufeng'
}
// 接口也可以繼承
interface speakable2{
    speak():void
}
interface speakChinese{
    speakChinese():void
}
class chinesePerson implements speakChinese {
    // 要同時(shí)實(shí)現(xiàn)接口及繼承接口的方法
    speakChinese() {}
    speak(){}
}

// 函數(shù)類(lèi)型接口
// 接口還可以用來(lái)約束函數(shù)
interface Discount {
    (price:number):number
}
function discount(price:number):number{
    reuturn price*.8
}
let d:Discount = discount(10)

// 可索引接口
// 可以對(duì)對(duì)象和數(shù)組進(jìn)行約束

interface UserInterface1 {
    [index:number]:string
}
let user1:UserInterface1 = ['a', 'b', 'c'] // 索引是數(shù)字

interface UserInterface2 {
    [index:string]:string
}
let user2:UserInterface2 = {name: 'zhufeng'} // 

泛型

在定義函數(shù)、接口或類(lèi)的時(shí)候,不預(yù)先指定具體的類(lèi)型,而是在使用的時(shí)候再制定類(lèi)型的一種特性

// T相當(dāng)于占位符,在函數(shù)使用的時(shí)候才傳進(jìn)來(lái)
function createArray<T>(length:number,val:T):t[] {
    let arr:T[] = []
    for (let i = 0;l<length;i++) {
        arr[i] = val
    }
    return arr
}

createArray<string>(3,'x')

類(lèi)數(shù)組

function sum(...args:number[]) {
    let a2:IArguments = arguments // arguments就是類(lèi)數(shù)組
}
sum(1,2,3)
// IArguments 相當(dāng)于一個(gè)接口
interface IArguments {
    [index: number]:any;
    length:number;
    callee: Function
}
let root = document.getElementById('root')
let children:HTMLCollection = root.children
let childNodes:NodeListOf<ChildNode> = root.childNodes

泛型類(lèi)

在類(lèi)中使用泛型

T = Type

 class MyArray<T>{
     list:T[] = []
     add(val:T) {
         this.list.push(val)
     }
     getFirst():T {
         return this.list[0]
     }
 }
let myArray = new MyArray<number>() // 使用時(shí)不寫(xiě)泛型也不會(huì)報(bào)錯(cuò),會(huì)進(jìn)行類(lèi)型推論
myArray.add(1);myArray.add(2)
let f = myArray.getFirst() // 1

// 泛型接口 就是在定義接口的時(shí)候使用泛型
interface SUM<T> {
    (a:T,b:T):T
}
let sum3:SUM<number> = function(a:number, b:number):number{
    return a+b
}
let r2 = sum3(1,2)

// 泛型可以有多個(gè)
// tuple 長(zhǎng)度和類(lèi)型都確定的數(shù)組
function swap<A,B>(tuple:[A,B]):[B,A] {
    return [tuple[1], tuple[0]]
}
swap<string,number>(['a',1]) // [1,'a']

// 默認(rèn)泛型類(lèi)型 T=number 默認(rèn)值
class MyArray<T=number>{
     list:T[] = []
     add(val:T) {
         this.list.push(val)
     }
     getFirst():T {
         return this.list[0]
     }
 }
let myArray = new MyArray<string>() // 使用時(shí)不寫(xiě)泛型也不會(huì)報(bào)錯(cuò),會(huì)進(jìn)行類(lèi)型推論
myArray.add(1);myArray.add(2)
let f = myArray.getFirst() // 1

// 泛型的約束
// 在函數(shù)中使用泛型的時(shí)候,由于預(yù)先不知道泛型的類(lèi)型,所以不能隨意訪問(wèn)相應(yīng)類(lèi)型的屬性和方法
function logger<T>(val:T) {
    console.log(val.length)// 這里不知道val的參數(shù)類(lèi)型,這樣寫(xiě)會(huì)報(bào)錯(cuò)
}
interface LengthWise{
    length: number
}
// T 要實(shí)現(xiàn)LengthWise這個(gè)接口,接口中定義了length的類(lèi)型
function logger<T extends LengthWise>(val:T) {
    console.log(val.length)
}

// 泛型類(lèi)型的別名
type Cart<T> = {list:T[]}|T[]
let cart:Cart<string> = ['a','b','c']
let cart2:Cart<string> = {list: ['a','b','c']}

// 泛型接口vs泛型類(lèi)型別名
// 接口會(huì)創(chuàng)建一個(gè)新的名字,它可以在任意地方被調(diào)用。而類(lèi)型別名并不是創(chuàng)建新的名字,例如報(bào)錯(cuò)信息就不會(huì)使用別名
// 類(lèi)型別名不能被extends 和 implements,這時(shí)我們應(yīng)該盡量使用接口代替類(lèi)型別名
// 當(dāng)我們需要使用聯(lián)合類(lèi)型或元組類(lèi)型的時(shí)候,類(lèi)型別名會(huì)更合適

解構(gòu)類(lèi)型系統(tǒng)

  • 接口的兼容性
    • 如果傳入的變量和聲明的類(lèi)型不匹配,TS就會(huì)進(jìn)行兼容性檢查
interface Animal {
    name: string;
    age:number;
    gender:number
}
let a:Animal={
    name: 'zhufeng';
    age:10,
    gender:0
}
interface Person {
    name:string;
    age:number
}
function getName(p:Person):string {
    return p.name
}
getName(a)
// getName 的參數(shù)p:Person是person類(lèi)型的接口,a是animal的接口,跟person接口相比,屬性多了一個(gè)gender屬性
// 在檢查參數(shù)類(lèi)型的時(shí)候,并不是比較接口類(lèi)型,而是比較具體的屬性是否兼容,對(duì)應(yīng)的屬性只能多,不能少

// 基本數(shù)據(jù)類(lèi)型的兼容性
let num:string|number;
let str:string;
num = str

// str2 賦值給num2 是因?yàn)閚um2 有toString方法,是個(gè)字符串,字符串可以給字符串賦值
let num2:{
    toString():string
}
let str2:string
num2 = str2

// 類(lèi)的兼容性
// 父子之間能不能賦值,跟是不是父類(lèi)子類(lèi)沒(méi)有關(guān)系,關(guān)鍵就看要的屬性有沒(méi)有
class Perent{
    name:string
}
class child {
    age:number
}
let p:Parent = new Person()
let c:Child = new Child()
// 將一個(gè)子類(lèi)的實(shí)例賦給父類(lèi)的變量
let pp:Parent = new Child()
// 將一個(gè)父類(lèi)的變量賦給一個(gè)子類(lèi)的變量
let cc:Child = new Parent()

// 函數(shù)的兼容性
// 比較函數(shù)的時(shí)候,先比較函數(shù)上的參數(shù),在比較函數(shù)上的返回值
// 參數(shù)是可以省略的
type SumFunc = (a:number,b:number)=>number
let sum:SumFunc;
sum = function(a:number,b:number):number{
    return a + b
}
sum2 = functon (a:number):number{
    return a
}
// 參數(shù)可以少不能多 
sum3 = functon ():number{
    return 0
}

// 這里可不是箭頭函數(shù),箭頭左邊是參數(shù)列表, 右邊是返回值,是一個(gè)對(duì)象,聲明的是屬性而不是值
// 返回值可以多,不能少,不然調(diào)用屬性的時(shí)候會(huì)報(bào)錯(cuò)
type GetPerson = () => {name: string,age:number}
let getPerson:GetPerson = function() {
    return {name: 'zhufeng',age:10}
}

// 函數(shù)參數(shù)的雙向協(xié)變
// 函數(shù)的參數(shù)中目標(biāo)兼容源,或者源兼容目標(biāo)都可以,只有一個(gè)成立就可以
type LogFunc= (val:number|string)=>void
// LogFunc 兼容下面的 log1
let log1:LogFunc;
log1 = function(val:number) {console.log(val)}
// log2 兼容上面的LogFunc
log2 = function(val:number|string|boolean) {
    console.log(val)
}

// 泛型的兼容性
// 泛型在判斷兼容性的時(shí)候,會(huì)先判斷具體的類(lèi)型,再進(jìn)行兼容性的判斷
interface Empty<T> {}
let x1:Empty<string>
let y1:Empty<number>
x1 = y1

interface NotEmpty<T> {data:T}
let x2:NotEmpty<string>={data: '123'}
let y2:NotEmpty<number>={data:123}
x2 = y2

// 枚舉的兼容性
// 枚舉和數(shù)字兼容  比較值
enum Colors {
    Red, // 0
    Yellow, // 1
    Blue // 2
}
// 相當(dāng)于
// let Colors ={ '1': Red,'2': Yellow; '3': Blue}

let num:number = Colors.Red // 0

let c:Colors;
c = Colors.Red
c = 1
// 數(shù)字可以賦值給枚舉變量,枚舉變量也可以賦值給數(shù)字 

類(lèi)型保護(hù)

類(lèi)型保護(hù)就是一些表達(dá)式,他們?cè)诰幾g的時(shí)候就能通過(guò)類(lèi)型信息確保某個(gè)作用域內(nèi)變量的類(lèi)型

類(lèi)型保護(hù)就是能通過(guò)關(guān)鍵字判斷出分支中的類(lèi)型

// 分支中判斷類(lèi)型
function double(input: string|number|boolean) {
    if (typeof input === 'number') {
        return input*2
    }
    if (typeof input === 'string') {
        return input+input
    }
    if (typeof input === 'string') {
        return !input
    }
}

class Bird{
    name1: string
}
class Dog {
    name2: string
}
function getName(animal:Bird|Dog) {
    if (animal instanceof Bird) {
        return animal.name1
    }
    if (animal instanceof Dog) {
        return animal.name2
    }
}

// null保護(hù)
// 在默認(rèn)情況下 null的檢查是不嚴(yán)格的
function getFirstLetter (str: string|null) {
    // 第一種處理方式
    str = str || ''
    return str.charAt(0)
}

// 鏈判斷運(yùn)算符 ES2020
// 是一種先檢查屬性是否存在你,再嘗試訪問(wèn)改屬性的運(yùn)算符,符號(hào)位?
// 原理就是三元運(yùn)算符
let a:any={
    b:'zhufeng'
}
a = null
console.log(a?.b) // 'zhufeng'
console.log(a == null?undefined:a.b)

// 可辨識(shí)的聯(lián)合類(lèi)型
// 就是利用聯(lián)合類(lèi)型中的共有字段進(jìn)行類(lèi)型保護(hù)的一種技巧
// 相同字段的不同取值就是可辨識(shí)
// 在聯(lián)合屬性中,通過(guò)相同的值來(lái)判斷 class
interface WarningButton {
    class:'warning',
    text1: '修改'
}
interface DanagerButton {
    class:'danager',
    text2: '刪除'
}
type Button = WarningButton | DangerButton
function getButton(button:Button) {
    if (button.class == 'warning') {
        console.log(button.text1)
    }
    if (button.class == 'danger') {
        console.log(button.text2 )
    }
}

interface Bird {
    swing:number
}
interface Dog {
    leg: number
}
// 判斷屬性有沒(méi)有
function getNumber(animal:Bird|Dog) {
    if ('swing' in animal) {
        console.log(animal.swing)
    }
    if ('leg' in animal) {
        console.log(animal.leg)
    }
}

// 以dog bird為例-----------------------------

// 自定義類(lèi)型檢查函數(shù) x is Bird類(lèi)型謂詞
function isBird (x:Bird|Dog):x is Bird {
    return (x as Bird).swing>0
    return (<Bird>x).swing>0 // 使用斷言,只能用Bird或者Dog
}
// 如果是鳥(niǎo)的話,返回鳥(niǎo)的翅膀的個(gè)數(shù),如果是狗的話,返回狗的腿的個(gè)數(shù)
function getAnimal (x:Bird|Dog) {
    if(isBird(x)) {
        console.log(x.swing)
    } else {
        console.log(x.leg)
    }
}

類(lèi)型變換

// 交叉類(lèi)型
// 將多個(gè)類(lèi)型合轉(zhuǎn)成一個(gè)類(lèi)型
interface Bird {
    name:string,
    fly():void
}
interface Person {
    name:string;
    eat():void
}
// 取的是接口中屬性的并集
type BirdMan = Bird & Person
// 里面的屬性一個(gè)都不能少&, |可以少
let bm:BirdMan = {
    name:'zhufeng',
    fly(){}
    eat(){}
}
// 兼容性檢查,僅在傳參的時(shí)候可以去那樣判斷,屬性可以多,但賦值的時(shí)候不行
type People = {
    name:string,
    age:number
}
let p:People = {
    name: 'zhufeng',
    age: 10,
    gender: 'male'  // 屬性不能多
}
// ----------------
let p = {
    name:'zhufeng',
    age: 10
}
// 用一個(gè)對(duì)象來(lái)定義一個(gè)類(lèi)型,再用類(lèi)型類(lèi)限制變量p
type People = typeof p
let p:People ={
    name: 'zhufeng',
    age:10
}

// 索引訪問(wèn)操作符
interface Person{
    name:string;
    age:number
    job: {
        name:string
    },
     hobbies:{name:string, level:number}[]
}
let job:Person['job'] = {name: '前端'}
let hobbyLevel:Person['hobbies'][0]['level'] = 10

// keyof
// 索引類(lèi)型查詢操作符
interface Person {
    name:string;
    age:number;
    gender: 'male'|'female'
}
function getValueByKey(p:Person,key:string) {
    return p[key]
}
// 接口中的key
getValueByKey(p:Person,key:keyof Person) {
    return p[key]
}
let p:Person = {
   name: 'zhufeng',age:10,gender:'male' 
}
let r = getValueByKey(p,'name') // zhufeng

// 映射類(lèi)型
// 在定義的會(huì)后用in操作符去批量定義類(lèi)型中的屬性
interface Person {
    name:string;
    age:number;
    gender?: 'male'|'female'
}
// ? 屬性可選的意思
type PartPerson = {
    [key in keyof Person]?:Person[key]
    // 相當(dāng)于每個(gè)屬性后面加個(gè)?
}
let p:Person = {
    name:'zhufeng',
    age:10,
    gender:
}
let p:PartPerson={
    // 參數(shù)少傳也不會(huì)報(bào)錯(cuò)
}

// partial 把屬性變成可選
let p: Partial<Person> = {
    
}
// required 將傳入的屬性變成必選項(xiàng),用-? 表示
// Reaonly 通過(guò)為傳入的屬性每一項(xiàng)都加上readonly修飾符來(lái)實(shí)現(xiàn)
// pick 能夠從傳入的屬性中摘取某一項(xiàng)返回
Pick<Animal,'name'> // 從animal中去name屬性
    
// 條件類(lèi)型
// 在定義泛型的時(shí)候能夠添加邏輯分支,以后泛型更加靈活
interface Fish {
    name1:string
}
interface Water {
    name2:string
}
interface Bird {
    name3:string
}
interface Sky {
    name4:string
}
type Conditon<T> = T extends Fish?Water:Sky
let con:Condition<Fish> = {name2: 'water'}
// 相當(dāng)于 let con:Water = {name: 'water'}






最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容