TypeScrict记录

50个最新TypeScript面试题合集 – TypeScript开发教程-srcmini

ts类型总结: TypeScript高级类型入门手册:附大量代码实例(收藏!)

一、环境安装与运行:

node环境+全局安装npm -g install typescript

新建文件夹→新建test.ts→写代码
运行(先将ts文件转为js文件):
tsc test.ts  自动生成  test.js  再执行 node test.js 即可

或者安装 cnpm install -g ts-node
ts-node first.ts


方式二:
新建立一个项目TSTest,在桌面新建立一个文件夹,然后在VSCode中打开。
打开终端,输入npm init -y,创建package.json文件
在终端中输入tsc --init,创建tsconfig.json文件
安装 cnpm install -g ts-node
修改tsconfig.json配置rootDir和outDir.
新建src文件夹,在里边建立index.html,page.ts文件
编写index.html文件,并引入page.ts文件
编写page.ts文件。
ts-node page.ts

类型汇总

string、number、boolean、object、array
any、unknown、void、never,bigint,symbol
字面量、元祖、枚举、

非严格模式下,undefind和null可以赋值给类型为string或number的变量

never:不存在的值(null/undefined都不符合)定义函数返回值较多,且这个函数是一个抛出错误的函数。
例: function test(msg:string):never{ throw new Error(msg) } //总是抛出错误

object: 只能用于json对象或数组或Date()
例子:let obj: object; obj={'xx':123}或obj=[123]

unkown:未知的类型,不可以赋值给任何类型,除非类型断言后

对象类型:{age?:number,[propname:string]:any} //表示age属性可有可无,且可有额外属性
函数类型: let fn:(a:string,bstring)=>string
数组类型:let a:number[] 或 let a:Array<number> 或 (string|number)[]
元祖类型: let a:[string,number] //用于固定数组的长度和内部元素的类型

if (typeof a === 'string'){}
if(a as string){} // <string>a  说明a的类型断言为string

bigint
表示非常大的数字
let tnum:bigint = 100n


symbol
表示全局唯一
如
let test1 = symbol("name")
let test2 = symbol("name")
test1===test2 //结果是false

声明变量时,要标明变量的类型

//静态类型(基础静态类型),一旦定义数据类型就不可以改变
let value:string="hello word" 

//自定义静态类型:
interface mytype  {
    name:string,
    age:number
}
let myvalue : mytype ={
    name:"梨花",
    age:18
}
console.log(myvalue.name)

对象类型

对象:
let textvalue:{
    name:string,
    age:number
} = {
    name:"小花",
    age:18
}

数组
let arr:string[] = ['小红','小花']  //定义一个数组,内容必须是字符串
const arr2:(string|number)[] = ['dsafdsa',2200]
const arr3:{name:string,age:number}[] = [{name:'sdfafas',age:12}]

类
let Person {}
let myclass:Person = new Person()

函数(定义一个函数,返回类型必须是字符串):
let myfun:()=>strung = ()=>{return '小红'}

类型注解、类型推断

类型注解:手动标明变量的类型
类型推断:不需要标明变量的类型,ts能自动推断(定义json时的属性可以直接赋值,不需要标明类型)

类型断言:

方式一:<类型>变量名 如:<string>str
判断str是否为字符串,且打印字符串长度
(<string>str).length

方式二:值 as 类型
return (str as string).length //判断变量str是否为string类型,如果是则打印length,否则报错

//用法:比如函数接收一个参数,但不确定这个参数是字符串还是number,可以用类型断言来写对应的代码
function lxdy(params:(string|number)){
    let len = (<string>params).length  //先断言为字符串才有length属性
    console.log('len',len);
}

函数定义返回值的类型

function func(one:string,two:string):string{
    return one+two+1
}
let funcvalue = func('1','2')

如果没有返回值,类型是void

元组

即规定数组每一项的数据类型
let yarr:[string,number,string] = ['d',1,'f']

类型别名,自面量

类型别名(即自定义类型,用type定义):有一些类型很长,为类型另起一个名字

type direction = 'up' | 'down' | 'left' | 'right'
let useValeu:direction = 'up' //只能是上面的四个值

//定义对象类型
type objtype = {
    name:string,
    age:number
}
//使用:
let myobj:objtype = { //必须要有对应的属性和对应类型的值
    name:'xxx'
    age:18
}

//定义函数类型:
type mfun = (a:string,b;string) => string 
let use:mfun = use(a,b)


//定义交叉变量
interface myface{
    name:string,
    age:number
}
type myzi = myface & {age:number}
let person:myzi = {name:'xioaming',age:18}

type Ipartial = Partial(myface)
let person:Ipartial  = {name:'xioaming'} //创建少一个属性可以

type Iomit = Omit(myface,age)
let person:Ipartial  = {name:'xioaming'} //忽略某个属性可以

字面量
如let age:18 = 18 //等于其他值会报错

接口

定义:一系列抽象方法的集合
用关键字 interface 来定义
接口名称一般大写字母开头

interface Inter {  //名称为Inter的接口
    readonly id:number //不能修改id的值
    name:string
    age:number
    other ?:string //加个问号,表示可有可无
    [proname:string] :any  //(索引签名)key名称不固定但类型要为string,value 为任何类型
    say():string  //函数,返回类型是string
}

//约束对象
const inter:Inter ={  //定义这个,要收到接口Inter的约束
    name:'dssa',
    age:18,
    test:19,
    say:()=>{
        return ''
    }

}
//约束类
class myclass implements Inter {
    name='dssa';
    age=18;
    test=19;
    say(){
        return ''
    }
}
//接口的继承
interface Teacher extends Inter {
    teach(): string;
}
//使用
function tunc(inter:Inter){
    console.log(inter.name)
    console.log(inter.age)
    console.log(inter.test)
}

接口和类型别名区别

相同点:
1、可约束对象里面有什么属性或方法
2、都可扩展(type使用&,interface使用extends)

不同点:
1、type可以定义为其他基本类型、联合类型、数组等,接口只能定义对象 { }
2、定义同样的名称时候,type不会合并,interface会合并

类主要有属性、方法和构造函数
如子类和父类有相同的方法,则子类会覆盖父类的方法
如果子类写了构造函数,则在子类的构造函数中一定要调super()//(即调了父类的构造函数,不然会被覆盖)

class Animal {
    age:number;
    constructor(age:number){  
        this.age = age
    }
    say(){
        console.log('汪动物叫')
    }
    
}

class Dog extends Animal {
  name:string;
  constructor(age:number,name:string){  //构造函数中this指向新创的对象本省
    super(age:number)
    this.name = name
  }
  say(){
    super.say() //可调用父类的say方法
    console.log('汪汪汪')
  }
}
const dog1 = new Dog(2,'旺财')

类的访问类型

public:公用内部外部都能使用
protected:内部或者继承的类的内部可以使用
private:只能类的内部,若要修改可再设置类方法修改,外部再调这个方法
static:静态属性(直接用类型.名称访问,实例化的对象访问不了)

class firstcal {
    protected name="小明";
    public sayMY(){
        return this.name;
    }
}

类的构造函数

class Person {
    public name:string
    constructor(name:string){
         this.name = name
    }
}
//简写
class Person {
    constructor(public name:string){
     
    }
}
const person = new Person('4566')
console.log(person.name) //4566

class minPer extends Person {
    constructor(public age:number){
        super("你好")  //子类一定要调用super()
    }
}
const minperson = new minPer(18)
console.log(minperson.age)  //18
console.log(minperson.name) //你好

类的getter、setter、static

//私有访问域的变量外部不可以访问,则可以通过get、set获取或修改(也叫存取器)
//static 定义的方法或变量不需要new实例化,直接类名就可调用
class Person3 {
    constructor(private age:number){

    }
    get age_(){
        return this.age+10
    }
    set age_(age_:number){
        this.age=age_
    }
    static sayLove() {
        return "I Love you";
    }
}
let per3  = new Person3(18)
per3.age_ = 15
console.log(per3.age_)
console.log(Person3.sayLove())

抽象类

//抽象类只能被继承,不能实例化
//抽象方法只能在抽象类里,且没有方法体
//继承的类一定要重写这个抽象方法
abstract class cxFj {
    abstract skill()
}

class minCX extends cxFj{
    skill(){
        console.log("技能1")
    }
}
const minCX1 =  new minCX()

class minCX2 extends cxFj{
    skill(){
        console.log("技能2")
    }
}
const minCX12 =  new minCX2()
console.log(minCX1.skill())
console.log(minCX12.skill())

配置文件(tsconfig.json):

运行 tsc --init 生成
运行:tsc 则自动将ts文件转成js文件

修改里面的配置则可以生成对应的js文件
"include":["demo.ts"], //只运行demo.ts

"outDir": "./build",  /* 生成js文件的位置 */
"rootDir": "./src",  /*ts文件位置*/
"sourceMap": true,/* 生成map文件,部署前可开启,出错会显示转化前代码 */
noUnusedLocals:true //没有使用的变量不转化,并且提示错误

(编译选项详解)
https://www.tslang.cn/docs/handbook/compiler-options.html 

联合类型和类型保护(守卫)

//所谓联合类型,可以认为一个变量可能有两种或两种以上的类型

interface Waiter {
  anjiao: boolean;
  say: () => {};
}
interface Teacher {
  anjiao: boolean;
  skill: () => {};
}
function judgeWho(animal: Waiter | Teacher) {
  //类型断言
  if (animal.anjiao) { 
    (animal as Teacher).skill();
  }else{
    (animal as Waiter).say();
  }
  //in语法
  if ("skill" in animal) {
    animal.skill();
  } else {
    animal.say();
  }    
}

//typeof判断哪种类型
function add(first: string | number, second: string | number) {
  if (typeof first === "string" || typeof second === "string") {
    return `${first}${second}`;
  }
  return first + second;
}

//用instanceof判断是不是类
class NumberObj {
  count: number;
}
function addObj(first: object | NumberObj, second: object | NumberObj) {
  if (first instanceof NumberObj && second instanceof NumberObj) {
    return first.count + second.count;
  }
  return 0;
}

枚举

定义:用于表示固定的几个取值
例如 人的性别只有男或女

enum Status {
    mes,
    apa,
    dat
}

let val = Status.mes //0
let val = Status[0] //mes

//用法二
enum gtage {
    fame=3,  //如果不设置默认值,则默认会从0开始赋值,mfame则是1
    mfame
}
let enumT:gtage = gtage.fame // 4

//将枚举当作类型来使用
interface Mj {
    name:gtage //相当于 name:(gtage.fame|gtage.mfame) 即name:(3|4)
}
class use implements Mj{
    name:gtage.fame = 3
}

泛型

泛型,定义的时候不确定类型,调用的时候才来确定
//函数中使用泛型
function fanx2<T>(first:T,second:T){
    return `${first}${second}`
}
//类中使用中泛型
interface girsface {
    name:string
}
class selectgirs<T extends girsface> {
    constructor(private girs:T[]){}
    girsname(index:number):string{
        return this.girs[index].name
    }
}
let myneed = new selectgirs([{name:"dsafsa"},{name:"dsfds5"}]);
console.log(myneed.girsname(1))


//约束泛型(虽然数据类型不确定,但传入的参数一定要含有某个属性,如length)
interface maface {
    length:number
}
function echoLength<T extends maface>(arg:T):T{
    let length = arg.length
    console.log(length);
    return arg
}
let result3 = echoLength({length:10})
let result4 = echoLength([1,2])

//泛型接口
interface Ifxjk<T1, T2> {
  name: T1;
  age: T2;
}

let userFxjk: Ifxjk<string, number> = {
  name: "电饭锅",
  age: 12
};

//泛型类
class fxle<T1, T2> {
  name: T1;
  age: T2;
  constructor(name: T1, age: T2) {
    this.name = name;
    this.age = age;
  }
}

let fxleue = new fxle<string, number>("小米", 12);//写法一
let fxleue: fxle<string, string> = new fxle("小米", "12");//写法二

//类型参数约束(将泛型T的键值作为K的类型)
function lxca<T, K extends keyof T>(obj: T, key: K) {
  return obj[key];
}

lxca({ a:1,b:2}, "b"); //第二个参数的值只能是a或b

命名空间

创建命名项目:
新建文件夹demo→建src和build和html文件
生成两个配置文件:npm init -y 和 tsc --init
在tsconfig.json中配置
html要引入对应编译后的js文件

命名空间
项目开发过程中,我们会发现我们的命名是有严格规范的,我们不能随意的去起名字,但若是都采用尽量标准化的方式去命名,我们又无法避免的会造成污染,TypeScript提供了namespace 避免这个问题出现
在TS1.5之前被叫做内部模块,主要用于组织代码,避免命名冲突
本质就是定义一个大对象,把变量/方法/类/接口...的都放里面
通过 export 导出
通过 namespace 定义

命名空间.ts
export namespace D {
    export const val = 'xxxxxx'
}

//使用.ts
import { D } from '路径'
console.log(D.val)


//使用三斜杆语法导出和导入命名空间
//nameapsce.ts:
namespace ns {
    export const val = '1111'
}

//使用
///<reference path="路径.ts" />
console.log( ns.val )


export namespace Components {
    export namespace SubComponents {
        export class Test {}
    }
    export class Header {
      constructor() {
        const elem = document.createElement("div");
        elem.innerText = "This is Header";
        document.body.appendChild(elem);
      }
    }
  
    export class Footer {
         new Header()
    }
  }


新建立一个项目TSTest,在桌面新建立一个文件夹,然后在VSCode中打开。
打开终端,输入npm init -y,创建package.json文件
在终端中输入tsc --init,创建tsconfig.json文件
修改tsconfig.json配置rootDir和outDir.
新建src文件夹,在里边建立index.html,page.ts文件
编写index.html文件,并引入page.ts文件
编写page.ts文件。

使用percel打包

index.html 直接引入ts文件:
<script src="./page.ts"></script>

安装:
yarn add --dev parcel@next

package.json:
{
  "scripts": {
    "test": "parcel ./src/index.html"
  },
}

运行:yarn test

忽略引入jq时编译器报错

declare var $: any;


2、声明函数时,要标明返回数据的类型
3、引用类型有 Array、new String、date、正则表达式
4、字符串的方法有.length  .indexOf()  . lastIndexOf()  .剪切.substring("2","3")    替换.repalce("你好","我好")
5、变量的作用域:局部变量 和全局变量。。元祖

6、什么是类,一种事物的集合,有属性和构造函数

7、通过new 一个类生成的实例叫对象

class XiaoJieJie{  //类
    name:string;
    age:number;
    constructor (name:string,age:number){
        this.name = name;
        this.age = age;
    };
    say(){
        console.log("你好这里是南方航空!")
    }
}
let recall:XiaoJieJie = new XiaoJieJie("小红",20)   //对象
console.log(recall)
recall.say()

8、修饰符:public(都可访问)、protested(本类和子类可访)、private (本类可访)

9、继承

class JsShuai extends Jspang{
    public xingxiang:string = '帅气'
    public zhuangQian(){
        console.log('一天赚一个小目标')
    }
}
let shuai = new JsShuai("技术帅",5,'演讲')
shuai.interst()   //使用父类的方法
shuai.zhuangQian()  //调用子类自身扩展的方法

10、重写,在子类重写父类的方法,方法名要一样

11、接口 interface Husband{   }

12、命名空间:

namespace shuaiGe{
    export class Dehua{
        public name:string = '刘德华'
        talk(){
            console.log('我是帅哥刘德华')
        }
    }
}
let dehua1:shuaiGe.Dehua   = new shuaiGe.Dehua()

dehua1.talk()

13、tsconfig

include:[./src/**/**] //需要编译的文件路径
exclude:[./src/**/**] //不需要编译的文件路径
complieoptions:{
target:'es6',//将ts代码编译成什么语言
strict:true,//所有严格模式的总开关
moudle:'es6',//使用es6的模块化方式
outDir:'./dist/'//编译后端代码位置
allowJs:false,//是否编译js文件
checkJs:false,//是否检查js文件的代码语法
removeComments:true,//是否去除注释编译
noEmit:false//是否生成编译后的js文件
alwaysStrict:false,//编译后的js文件是否启用严格模式
noImplicitAny:false,//是否不能出现any类型
strictNullChecks:true,//是否严格检查空值

}

函数

//匿名函数
const func = function(a:number,b:number):number{ return a+b }

//函数
function func(a:number,b:number){ return a+b }

//箭头函数
const func = (a:number,b:number)=> a+b 

//接口函数
type myFunc = (a:number,b:number)=> number
const func:myFunc = (a:number,b:number)=> a+b 

//默认参数、可选参数
const func = (a:number=1,b?:number,...arg:any[])=>{}

//构造函数
const myFun = new Function(a,b,'return a*b')
myFun(2,3) //6

//递归函数
function sum(arr:number[],n:number):number{
    if(n<=0){
        return 0
    }else{
        return sum(arr,n-1)+arr[n-1]
    }
}
//计算数组前2行的总和
sum([1,2,3],2)

函数重载

函数重载:函数名相同,参数、参数的个数、参数的类型,函数的返回类型可不同
用处:某些函数的参数类型或个数不一样,但函数体的写法相同,可以用到重载

function start(s1:string):void
function start(n:number,s1:string):void
function start(x:any,y?:any):any{
    console.log(x)
    console.log(y)
}

start('小米')

索引类型

//索引类型
let obj1 = {
  name: "小红",
  age: 16
};

//传入key返回所有对应的value
function getObjForKey<T, K extends keyof T>(obj: T, keys: K[]): T[K][] {
  let arr = [] as T[K][];
  keys.forEach(res => {
    arr.push(obj[res]);
  });
  return arr;
}
console.log("getObjForKey: ", getObjForKey(obj1, ["name", "age"]));

//条件类型
//相当与条件运算符,常用于处理重载函数
interface Inter {
    name:string
}
interface Face {
    age:number
}

//如果T是string类型,则Contion<T>是 Inter否则 是 Face
type Contion<T> = T extends string ? Inter : Face

function reload<T extends number|string>(val:T):Contion<T>{
    throw "
}

//分布式类型:被检测出是联合类型的称为分布式类型
//剔除某个类型
type res = Exclude<string|number|boolean,number> //剔除number

//剔除null或undefined
type res = NonNullable<string|number|undefind> //undefind会被剔除

//获取函数返回值的类型
type res = ReturnType<()=>number>

//将类的构造函数的参数变为元组
type res = ConstructorParameters<typeof Person>

//将函数的参数作为元祖
type res = Parameters<typeof fun>

infer关键字

type ElementOf<T> = T extends Array<infer E> ? E:T
(解析:infer E代表数组的类型)
type res1 = ElementOf<string[]> //则res1是string类型

映射类型

映射类型:将原有的类型映射出新的类型,如将原来型的属性的只读属性去除
interface yspro {
    name:string
    age:number
}

type newyspro = Readonly<yspro> //为每一个属性加上只读属性
type newyspro2 = Partial<yspro> //为每一个属性加上可选属性
type newyspro3 = Required<yspro> //为每一个属性加上必须要有属性

//Record:
type Name = "xiaomi"|'huawei'
type Person = {
    name:string
    age:number
}

type newtype = Record<Name,Person>//哪个需要作为键值则放在第一个参数
let res:newtype = {
    xiaomi:{
        name:'mi'
        age:18
    },
    huawei:{
        name:'hua'
        age:19
    }

}

//Pick:将部分属性类型映射
let res = Pick<yspro,name> //仅映射name属性

//Omit
let res = Pick<yspro,name> //不要映射name属性

//OmitThisParameter:从T中剔除this参数类型
function fo(this:object,x:number){}
type T0 = OmitThisParameter<typeof fo> //(x:number)=>void
type T2 = OmitThisParameter<string> //string  传入什么类型就是什么类型

装饰器

//装饰器是一种特殊类型的声明,它能够被附加到类,方法,访问器,属性或参数上。用 @ 添加
//必须在命令行或 tsconfig.json 里启用 experimentalDecorators 编译器选
//装饰器工厂:如果我们要定制一个修饰器如何应用到一个声明上,我们得写一个装饰器工厂函数。 装饰器工厂就 
//是一个简单的函数,它返回一个表达式,


//函数装饰器
//@zsqHs应用于普通函数 target是prototype
//@zsqHs应用于静态函数 target是类的构造函数
function zsqHs(target: any, key: string, desciptor: PropertyDescriptor) {
  console.log("desciptor: ", desciptor);
  desciptor.value = () => {
    return "自定义返回值";
  };
}

class Zsq {
  constructor(public name: string) {
    this.name = name;
  }
  @zsqHs
  showName() {
    return this.name;
  }
}

let zsq = new Zsq("nihao");
console.log("showName", zsq.showName()); //自定义返回值

//类的属性装饰器(只有两参数)
function sxzsq (target: any, key: string){

}

//类的构造函数的参数装饰器
function cszsq (target: any, key: string,index:number){

}
class Zsq {
  name: string
  constructor(@cszsq name: string) {
    this.name = name;
  }
}


//装饰器的使用
function useZsq (msg:string){
    return function (target:any,key:string,desciptor: PropertyDescriptor) {
        const fn = desciptor.value
        try(){
            fn()
        }carch(e){
            console.log(msg)
        }
    }
}
const testVla:string = "real name"
class Zsq {
  name: string
  constructor( name: string) {
    this.name = name;
  }
  @useZsq
  show(){
    return testVla
  }
}

模块的导入与导出

JS:
//这里导出和导入名称和不一致
export default xxx
import ooo from '路径'

//导入导出名称需要一致
export const xxx
import { xxx } from '路径'

node模块
exports.xxx = xxx
const xxx = require("路径")
const { xxx,xxx } = require("路径")

module.exports.xxx = xxx
const xxx = require("路径")
const { xxx } = require("路径")

TS模块
方式一:
export const xxx
import { xxx } from '路径'

方式二:
export interface xxx { }
import ooo = require("路径") 
//使用 ooo.xxx

描述文件

在开发的过程中引用第三方插件工具的时候,在js里面是可以直接使用它的方法或属性,
但在ts文件里面却用不了且识别不了类型,这个时候就要用到类型描述文件,
以.d.ts为文件后缀名

很多流行的第三方库的声明文件不需要我们定义了
https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types
https;//www.typescriptlang.org/dt/search?search=

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值