赞
踩
提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:第一章 Python 机器学习入门之pandas的使用
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
点击查看参考csdn
接口可多继承(接口内有同样类型名,但类型不同,则不可继承),类不行
class School{ private b:string='ss' } //报错 // class Student implements test1{ // c=2 // a='' // } //正常 class Student extends School implements test1{ c=2 a='' } interface test1 extends School{ a:string }
点击查看参考csdn
语法格式:
(1) <类型>值
(2)值 as 类型
注意:
1. 类型断言更像是类型的选择,而不是类型的转换
2. 联合类型:我们只能访问此联合类型的所有类型里共有的成员。
//这是错误的代码 //那么就是说,length应该是string和number共有的属性才对, //但是number没有length的属性,所以上述代码放在ts文件里, //if语句中的length就会报错(“number”上不存在属性“length”) function func(val: string | number) :number { if (val.length) { return val.length } else { return val.toString().length } } //正确要先判断类型 function func(val: string | number) :number { if (typeof val == 'string' && val.length) { return val.length } else { return val.toString().length } }
interface a{ b:string } interface b{ c:string } interface c extends a,b{ d:string } class e implements c{ d='' b='' c='' } //使用类型断言可以初始化空,后面可以单独初始化 let f:c=<c>{} f.b=' ' //会报错 let f:c={}
//type是用来定义新类型,常结合typeof使用
type FType = boolean | string | number;
type Shape = { name: string }
type Circle = Shape & { radius: number }
function foo(circle: Circle) {
const name = circle.name
const radius = circle.radius
}
点击查看参考csdn
类型声明的作用?
下面是对原有的js提供类型
declare let age: number;
declare function getAge(): number | string;
declare class Person { };
下面是定义纯粹的类型
//纯粹定义类型,要结合type,declare 可有可无
declare type dd = {
a:string
}
declare type sd = string
如果.d.ts文件过多或类型过多,可以使用module,
utilTypes.d.ts文件
declare module "cc"{
export declare type dd = {
a:string
}
export declare type sd = string
}
test.ts文件
import { dd } from "cc"
let aa:dd= {
a:"11"
}
如果不使用module,可以直接使用,不用导入
如果.d.ts文件不在根目录下,需要在tsconfig.ts配置include
{
"compilerOptions": {
},
"include": ["src/**/*.ts", "src/**/*.vue", "src/**/*.tsx", "src/**/*.d.ts"], // **Represents any directory, and * represents any file. Indicates that all files in the src directory will be compiled
"exclude": ["node_modules", "dist"] // Indicates the file directory that does not need to be compiled
}
添加链接描述
重点记住下面几个
//Record:生成接口类型,然后我们使用传入的泛型参数分别作为接口类型的属性和值 //源码 type Record<K extends keyof any, T> = { [P in K]: T; }; //使用 type MenuKey = 'home' | 'about' | 'more'; interface Menu { label: string; hidden?: boolean; } const menus: Record<MenuKey, Menu> = { about: { label: '关于' }, home: { label: '主页' }, more: { label: '更多', hidden: true }, };
//可以从类型中选取出指定的键值,然后组成一个新的类型 //源码 type Pick<T, K extends keyof T> = { [P in K]: T[P]; }; //使用 // 定义一个通用的 Person 类 interface Person { name: string; age?: number; weight?: number; } type NewPerson = Pick<Person, 'name' | 'age'>; // 相当于 interface NewPerson { name: string; age?: number; }
Omit
//返回去除指定的键值之后返回的新类型 //源码 type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>; //使用 // 定义一个通用的 Person 类 interface Person { name: string; age?: number; weight?: number; } type NewPerson = Omit<Person, 'weight' | 'name'>; // 相当于 interface NewPerson { age?: number; }
为接口或type增加新key
//一 type user ={ name:string age:number sex:string } type newuser ={dqwd:number} & user //二 // type MyType { key: string; value: number; } // 新类型必须使用interface,type无法使用继承 interface NewMyType extends MyType { newKey: number; }
扩展:使用&不当可能会出现错误
type aa=string | number type c=aa & string //string interface aa{ a:number b:string } interface cc{ a:string } //a属性编程never无法赋值,报错 let c:aa & cc={ b:'', }
接口修改key或keyi的类型
思路:新的key名字随意,直接修改不太好做到,可以先剔除需要修改的key在增加即可
type user ={
name:string
age:number
sex:string
}
//写成通用函数有难度,下面的简单
type Sx = Omit<user,"name"> &{"hahah":number}
新的key名字包含原来修改的key名字
修改一个
//T是接口,K是修改的key,写死getkey
type ChangeOneKey<T extends {[p :string]:any},K extends keyof {[p :string]:any}> = {
[p in keyof T as `get${keyof Pick<T,K>}` | keyof Omit<T,K>]: T[p]
}
//从 T 中剔除可以赋值给 U 的类型,如果 T 是 U 的子类型,则返回 never 不是则返回 T
//源码
type Exclude<T, U> = T extends U ? never : T (会遍历T的每一个类型进行判断)
普通判断不会遍历,注意区分
```javascript
type A = number | string | boolean
type B = number | boolean
type ssss= A extends B ? never : A
//ssss: number | string | boolean
//使用
type A = number | string | boolean
type B = number | boolean
type Foo = Exclude<A, B>
// 相当于
type Foo = string
或使用 extends
```javascript
type sadqwq = "1"|"2"|"333"
function pluck<T, K extends sadqwq>(a:T,b:K):void{
console.log(b);
}
pluck(2,"2")
keyof和in
keyof
前言:类型不可以作为值传递,即不可以打印,想要查看可以先注解一个变量,鼠标放上去就可以看到类型
type Person = {
id: number;
name: string;
age: number;
};
type P1 = keyof Person; //'id' | 'name' | 'age'
type P2 = Person[keyof Person]; // number | string
1. Person['key'] 是查询类型(Lookup Types), 可以获取到对应属性类型的类型;
2. Person[keyof Person]本质上是执行 Person['id' | 'name' | 'age'];
3. 由于联合类型具有分布式的特性,Person['id' | 'name' | 'age'] 变成了 Person['id'] | Person['name'] | Person['age'];
4. 最后得到的结果就是 number | string.
in看成forin循环,被 in 进行(遍历)运算的都是联合类型
type cc= { [P in 'x' | 'y']:P }//P进行了两次遍历,每次遍历P都不一样
//结果
type cc = {
x: "x";
y: "y";
}
& | 都可以看做联合类型,&用于接口联合,| 可以用做普通类型
string | number
string & number //错误
type z= {a:string} & {b:string} //自定义类型z必须要有a b 两个属性
联合类型 |
当联合类型是类的联合时,One | Two 只能使用两个类中共同的方法
class One{ public up(){ console.log("up"); } public say(){ console.log("One say"); } } class Two{ public down(){ console.log("down"); } public say(){ console.log("Two say"); } } let one=new One() let two = new Two() let three:One|Two=<One| Two>{} three['say']=one['say'] //three.say=one['say'] 共有方法怎么定义都可以 three["up"]=one['up'] //three.up=one['up'] 会直接爆红,上面定义不会爆红,调用时才爆红 three.say()
extends 较为复杂,不仅仅代表继承
type c= string | number
type a=number
type b=string | number
type g= object
//左边小类型可以赋给右边大类型,取值第一个
type d= a extends c? never: ' ' //never
type e= b extends c? never: ' ' //never
type f= b extends c? never: ' ' //never
type h= g extends c? never:'' //''
//注意是接口类型或对象类型时,只有相同时,左边才能赋值给右边
添加链接描述
ts不允许对象动态
let studet={
a:2
}
studet.cc=3 //报错
studet['cc']=3 //虽然不报错,但访问还是会报错,不存在改属性
log(studet.cc)//不存在改属性
可以加一个接口,实现自定义增加属性
interface studet{
[key:string]:number
}
let studet:studet={
a:2
}
studet.cc=3 //不会报错
添加链接描述
添加链接描述
1.重写方法名和参数(包括类型)不能改变,
2.重载方法名相同,参数必须不同(可以仅仅类型不同)注意:必须要把精确的定义放在前面,最后函数实现时,需要使用 |操作符或者?操作符,把所有可能的输入类型全部包含进去,以具体实现。 即最下面的方法需要兼容上面的方法
//重载
function run(num:number):void;
function run(str:string,flag:boolean):void;
function run(str:string,flag?:boolean):void;
function run(str:number|string,flag?:boolean):void{
if(typeof str === 'string'){
console.log("fur")
}else{
console.log(1)
}
}
run(1)
run("fur")
run("fur",true);
添加链接描述
结论:类装饰和属性装饰器同是在运行时调用,方法装饰器是在方法调用时调用
类装饰 例如声明一个函数 addAge 去给 Class 的属性 age 添加年龄. function addAge(constructor: Function) { constructor.prototype.age = 18; } @addAge class Person{ name: string; age!: number; constructor() { this.name = 'huihui'; } } let person = new Person(); console.log(person.age); // 18
方法装饰:类似Object.defineProperty(几乎一样),在方法调用时调用(方法调用之前)。 接受三个参数 target : 静态成员 :类的构造函数 实例成员 :类的原型对象 method : 成员的名字 descriptor : 成员的属性描述符 应用:函数调用日志 class Techer extends Proper{ constructor(){ super() } @log a(c:number|string):string{ console.log("aaa"); return '1111' } } function log(target:Object, name:string, descriptor:any) { var oldValue = descriptor.value; console.log(" descriptor.value", descriptor.value); descriptor.value = function () { //arguments是name函数的参数 console.log(`Calling "${name}" with`, arguments); //注意此时修改了原函数this指向,实例调用带有此注解的方法,this指向null oldValue.apply(null, arguments); } // return descriptor; } let techer=new Techer() techer.a('c') //调用见图 techer.a('d')
装饰器工厂需要调用并返回一个装饰器
执行顺序 当多个装饰器应用于一个声明上,将由上至下依次对装饰器表达式求值,求值的结果会被当作函数,由下至上依次调用,例如如下: function f() { console.log("f(): evaluated"); return function (target, propertyKey: string, descriptor: PropertyDescriptor) { console.log("f(): called"); } } function g() { console.log("g(): evaluated"); return function (target, propertyKey: string, descriptor: PropertyDescriptor) { console.log("g(): called"); } } class C { @f() @g() method() {} } // 输出 f(): evaluated g(): evaluated g(): called f(): called
类可以作为类型,(包括继承父类)
如果类有私有属性或私有方法,则只能用来限定该类的实例
只读属性
class Mytest{
readonly a:number=2
}
抽象类继承抽象类,子抽象类可以实现父类抽象方法也可以不实现(实现没啥用),但具体类必须实现
抽象类和类可访问性都是父级大于等于子集
注意:编译后的js都要引入
添加链接描述
//官网例子
function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] {
return names.map(n => o[n]);
}
interface Person {
name: string;
age: number;
}
let person: Person = {
name: 'Jarid',
age: 35
};
let strings: string[] = pluck(person, ['name']); // ok, string[]
function pluck<T, K extends keyof T>(o: T, names: K[]): T[] {
// return names.map(n => o[n]);
//会报错,数组里的类型不能写死
return [{name:'11',age:1}]
}
interface Person {
name: string;
age: number;
}
let person: Person = {
name: 'Jarid',
age: 35
};
let strings = pluck(person, ['name']); // ok, string[]
nver类型不可以被赋值
//初始化数组时,没有定义每一项的类型,则被初始化成never类型,后面无法赋值
const bann = []
bann[1] = 2 //不能将类型“number”分配给类型“never”。
never用于对象(接口)等的属性(属性非属性值,例如:{a:1} 即a使never)时,属性被删除
type VariantA = {
a: string,
}
type VariantB = {
b: number,
}
declare function fn(arg: VariantA | VariantB): void
const input = {a: 'foo', b: 123 }
fn(input) // 这违背了我们的设计,但是 TypeScript 不会报警
type VariantA = { a: string b?: never } type VariantB = { b: number a?: never } declare function fn(arg: VariantA | VariantB): void const input = {a: 'foo', b: 123 } fn(input) // ❌ Types of property 'a' are incompatible
//无限个属性
interface objectInter{
//会报错
// name:string
[key:string]:number
}
let myobj:objectInter={
a:1,
b:2
}
//有限属性
interface Person { name: string; age: number; } type Optional<T> = { [K in keyof T]?: T[K] }; const person: Optional<Person> = { name: "Tobias" }; // in 它的语法与索引签名的语法类型,内部使用了 for .. in。 具有三个部分 type Nullable<T> = { [P in keyof T]: T[P] | null } type Partial<T> = { [P in keyof T]?: T[P] }
映射:in 与 联合类型连用
视频
笔记
as 对映射类型中的键进行重新映射
type aa=string | number type c=aa & string //string interface aa{ a:number b:string } interface cc{ a:string } //a属性编程never无法赋值,报错 let c:aa & cc={ b:'', }
Promise:Promise的泛型T代表promise变成成功态之后resolve的值,resolve(value)
添加链接描述
type sayType = <T>(operate: T, person: string, content: string) => boolean;
var say: sayType = function (operate, person, content) {
if (person === '' || content === '') return false;
console.log(`${person} ${operate}:${content}`);
return true;
};
say<string>('','','')
const foo = <T>(x: T): T => x; const foo = <T extends {}>(x: T): T => x; const foo = <T extends Record<string, unknown>>(x: T): T => x; //<T>(x: T) => T类型 x => x函数 const foo: <T>(x: T) => T = x => x; const identity = <T>(arg: T): T => { console.log(arg); return arg; }; const renderAuthorize = <T>(Authorized: T): ((currentAuthority: CurrentAuthorityType) => T) => ( currentAuthority: CurrentAuthorityType, ): T => { return };
函数表达式
ts中的 =>用来表达函数的定义: 左边是输入类型,需要用括号括起来,右边是输出类型
let kate3: (x: number, y: number) => number = function (x: number, y: number): number {
return x + y;
}
// ts中的 =>用来表达函数的定义: 左边是输入类型,需要用括号括起来,右边是输出类型
函数声明
function sayHi3(x:number,y:number): number {
return x + y
}
sayHi3(1,5)
// sayHi3(2,5,7) //Expected 2 arguments, but got 3.
// sayHi3(5) // An argument for 'y' was not provided.
接口限制函数
interface SayHi4 { (x: number, y: number): number; } let sayhi6: SayHi4 = function(x, y) { return x+y} 泛型接口 interface Search { <T,Y>(name:T,age:Y):T } let fn:Search = function (name id){ console.log(name, id) return name; } fn('li',11);//编译器会自动识别传入的参数,将传入的参数的类型认为是泛型指定的类型
剩余参数
可以使用 ...rest 的方式获取函数中的剩余参数(rest 参数)
function push(array: any[], ...items:any []) {
items.forEach(item => {
array.push(item)
})
}
let a: any[] = []
push(a, 1,2,3,4)
// 注意,这里写法是定义的方法哦 interface Search { <T,Y>(name:T,age:Y):T } let fn:Search = function <T, Y>(name: T, id:Y):T { console.log(name, id) return name; } fn('li',11);//编译器会自动识别传入的参数,将传入的参数的类型认为是泛型指定的类型 //写法定义的是属性 interface objType { money: (value: number) => number arr: () => string[] } const obj2: objType = { money: (val) => val, arr: () => ['1'], } console.log(obj2.money(2)) console.log(obj2.arr()) //接口使用泛型 interface objType<T1, T2> { money: (value: T1) => T1 arr: () => T2[] } const obj2: objType<number, string> = { money: (val) => val, arr: () => ['1'], } console.log(obj2.money(2)) console.log(obj2.arr())
infer语法的限制如下:
infer只能在条件类型的 extends 子句中使用
infer得到的类型只能在true语句中使用, 即X中使用
/**
* Obtain the return type of a function type
*/
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
type Last<Arr extends unknown[]> = Arr extends [...infer rest,infer Ele]? Ele : never;
添加链接描述
typeof作用:
1、可以拿到某个js文件类型
import XtxSwiper from './XtxSwiper.vue’
type xx = typeof XtxSwiper
2、可以拿到某个变量类型
typeof和数组使用 const arr12=[1,2,'s'] //type lei1 = (string | number)[] type lei1= typeof arr12 typeof和数组使用 const arr123=[1,2,'s'] as const //type lei2 = readonly [1, 2, "s"] type lei2= typeof arr123 typeof和函数使用 function add(a: number, b: number) { return a + b; } // (a: number, b: number) => number type AddType = typeof add; typeof和对象使用 const lolo = { name: "lolo", age: 7, address: { province: "福建", city: "厦门", }, }; interface Person { name: string; age: number; address: { province: string; city: string; }; } //type Person = { // name: string; // age: number; // address: { // province: string; // city: string; // }; //} type Person = typeof lolo; // type Address = { // province: string; // city: string; // } type Address = typeof lolo["address"];
不加as const const arr123=[1,2,'s'] //(number | string) [1, 2, "s"] type sadas=typeof arr123 加as const const arr123=[1,2,'s'] as const //readonly [1, 2, "s"] type sadas=typeof arr123 不加as const let aaa:string='sdad' //string type asdqda=typeof aaa 加as const let aaa:string='sdad' as const //'sdad' type asdqda=typeof aaa
数组的索引只能是number
数组 type asweq=(number|string)[] // string | number type dsad=asweq[number] // 1 | 2 type cds = [1,2][number] 接口 interface AnyObject { [key: string]: number } //number type dasdqwe=AnyObject[string] interface P{ a:string b:number } //报错 type dasdqwe2131=P[string] //1 type cdssad={ a:1 }['a']
type tesla = ['tesla', 'model 3', 'model X', 'model Y']
let ccsda:tesla=['tesla', 'model 3', 'model X', 'model Y']
ccsda.push('model Y')
ccsda.push('model 3')
//报错,元祖里面没有number类型
ccsda.push(3)
添加链接描述
逆变和协变都是型变,是针对父子类型而言的,非父子类型自然就不会型变,也就是不变
像 java 里面的类型都是通过 extends 继承的,如果 A extends B,那 A 就是 B 的子类型。这种叫做名义类型系统(nominal type)。而 ts 里不看这个,只要结构上是一致的,那么就可以确定父子关系,这种叫做结构类型系统(structual type)。
协变和逆变都是指可以成功的
协变:子可以赋值给父
逆变:函数才能实现(非官方,个人理解)
但是在 ts2.x 之前,也就是父类型可以赋值给子类型,子类型可以赋值给父类型,既逆变又协变,叫做“双向协变”
// 协变 interface Person { name: string; age: number; } interface Son { name: string; age: number; hobbies: string[] } let peo:Person={ name:'', age:1, } let son:Son={ name: '', age: 2, hobbies: [''] } //协变 peo=son //报错 son=peo //函数可以实现逆变 看链接
type A1 = 'x' extends 'x' ? string : number; // string
type A2 = 'x' | 'y' extends 'x' ? string : number; // number
type P<T> = T extends 'x' ? string : number;
type A3 = P<'x' | 'y'> // ?
分配条件类型:
意思就是对于使用extends关键字的条件类型(即上面的三元表达式类型),如果extends前面的参数是一个泛型类型,当传入该参数的是联合类型,则使用分配律计算最终的结果。分配律是指,将联合类型的联合项拆成单项,分别代入条件类型,然后将每个单项代入得到的结果再联合起来,得到最终的判断结果。
type P<T> = [T] extends ['x'] ? string : number;
type A1 = P<'x' | 'y'> // number
//层级 unknown 是顶层,never是最底层,any是墙头草
type A2 = P<never> // string
type:
type aa= 1 let c:aa=1 //报错 // aa=2 type z={ a:1 } let zz:z={ a:1, //报错 // b:2 } type xx=true let flage:xx=true //报错 // flage=false //可以使用扩展运算符,但不能使用运算符,类型不能运算 type arr1=unknown[] type arr2=unknown[] type Concat<T extends arr1,U extends arr2>=[...T,...U] //[1, 2] type xs=Concat<[1],[2]> //type限制函数, type typ2={ option<T>(c:T,d:number):number option1:<T>(a:T)=>string } type typ1={ option(c:string):number option1:<T>(a:T)=>string } //参数可加可不加,如果加必须符合类型 let casdzx:typ1={ option:()=>1, option1:()=>"" }
import type 是 TypeScript 2.9 版本引入的一种新的类型导入语法。虽然在某些情况下 import 和 import type 可以互换使用,但它们并不完全等价。具体来说,import type 只能用于导入类型,而 import 则可以用于导入任何类型的值(变量、函数、类等)。
如果你使用 import 导入一个模块中的变量、函数或类,那么这些值会被加载到当前文件的命名空间中,可以随时使用它们。而如果你使用 import type 导入一个模块中的类型,则仅在编译阶段使用该类型,并且不会在运行时加载任何额外的代码。
通常情况下,建议尽可能使用 import type 来导入类型,因为它可以帮助减小生成的 JavaScript 文件的大小,并且更加明确地表达你的意图。但是如果你需要同时导入类型和值,或者需要动态导入模块,那么就必须使用 import。
注意是接口声明合并,declare type 不能合并
例如合并接口sdd
untils.d.ts文件
declare module "helo"{
export interface sdd {
a:string,
b:string,
c:1
}
}
tee.d.ts文件
import * as untils from "helo"
declare module 'helo'{
export interface sdd {
c:number
}
export declare type ss= {
e:number
}
}
利用接口合并可以对npm包进行扩展
/* eslint-disable */
import * as axios from 'axios';
// 扩展 axios 数据返回类型,可自行扩展
declare module 'axios' {
export interface AxiosResponse<T = any> {
code: number;
data: T;
message: string;
type?: string;
[key: string]: T;
}
}
还可以对原对基本类型进行扩展,例如string(文件只要有一个export或import就是模块话文件)
这样可以骗过编译器,但是编译后的js无法运行
interface String{
'b':()=>void;
}
let a = "a"
a.b= ()=>{
console.log(1111);
}
a.b()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。