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'}