提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:第一章 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
}
}
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={}
f.b=' '
//会报错
let f:c={}
点击查看参考csdn
//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
类型声明的作用?
declare let age: number;
declare function getAge(): number | string;
declare class Person { };
添加链接描述
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都不一样
& | 都可以看做联合类型,&用于接口联合,| 可以用做普通类型
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={}
three['say']=one['say']
//three.say=one['say'] 共有方法怎么定义都可以
three["up"]=one['up']
//three.up=one['up'] 会直接爆红,上面定义不会爆红,调用时才爆红
three.say()
extends 较为复杂,不仅仅代表继承
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(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(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 = {
[K in keyof T]?: T[K]
};
const person: Optional = {
name: "Tobias"
};
// in 它的语法与索引签名的语法类型,内部使用了 for .. in。 具有三个部分
type Nullable = { [P in keyof T]: T[P] | null }
type Partial = { [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 = (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('','','')
添加链接描述
const foo = (x: T): T => x;
const foo = (x: T): T => x;
const foo = >(x: T): T => x;
//(x: T) => T类型 x => x函数
const foo: (x: T) => T = x => x;
const identity = (arg: T): T => {
console.log(arg);
return arg;
};
const renderAuthorize = (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: number, y: number) { return x+y}
泛型接口
interface Search {
(name:T,age:Y):T
}
let fn:Search = function (name: T, id:Y):T {
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 {
(name:T,age:Y):T
}
let fn:Search = function (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 {
money: (value: T1) => T1
arr: () => T2[]
}
const obj2: objType = {
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 any> = T extends (...args: any) => infer R ? R : any;
type Last = 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 extends 'x' ? string : number;
type A3 = P<'x' | 'y'> // ?
分配条件类型:
意思就是对于使用extends关键字的条件类型(即上面的三元表达式类型),如果extends前面的参数是一个泛型类型,当传入该参数的是联合类型,则使用分配律计算最终的结果。分配律是指,将联合类型的联合项拆成单项,分别代入条件类型,然后将每个单项代入得到的结果再联合起来,得到最终的判断结果。
type P = [T] extends ['x'] ? string : number;
type A1 = P<'x' | 'y'> // number
//层级 unknown 是顶层,never是最底层,any是墙头草
type A2 = P // 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,...U]
//[1, 2]
type xs=Concat<[1],[2]>
//type限制函数,
type typ2={
option(c:T,d:number):number
option1:(a:T)=>string
}
type typ1={
option(c:string):number
option1:(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。