TypeScript基础

Posted 转角90

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TypeScript基础相关的知识,希望对你有一定的参考价值。

数据类型

typescript会进行类型推导,不需要每个都写类型注释

数组

let list1:string[]=[\'aa\',\'bb\']  // 数组类型并且内容都为string
let list2:any[] = [\'aa\',1,3]
let list3:Array<string> = [\'aa\',\'aa2\',\'bb\']

枚举

enum Dict 
  UP=1<<1,  // 默认=0
  Down=1<<2,
  LEFT,
  RIGHT=\'ddd\'


const d1: Dict = Dict.UP

Object类型

type infoType = 
    name:string
    age:number
    y  // 任意类型
    x?: number // 可选
 

let info:infoType = 
    name:\'ss\',
    age:33,
    y:2,
    


let info2:Object =   // info2.name 报错 Object表示一个空对象
    name:\'ss\',
    age:33

Symbol类型

const s:symbol = Symbol(\'aaa\')

null和undefined

let a:null = null
let b:undefined = undefined

string

let s:string = \'aaa\'

函数类型

type infoType = 
    name:string
    age:number
  	

// 剩余参数类型 (...arg:number)
function foo(name:string,...arg:number[]): infoType[] 
    let info:infoType[] = []
    info.push(name:\'ss\',age:33)
    return info

匿名函数不需要进行类型注释,根据上下文会自动指定

any

let a:any = \'\'
a=3
console.log(a.length)  

unknown

与any的区别:

  • unknown类型进行任何操作都是不合法的

  • any类型任何操作都是合法的

  • unknown类型必须进行校验

let a:unknow = \'\'
console.log(a.length)  // 报错

// unknow类型必须进行校验, 类型缩小
if (typeof a === \'string\') 
	console.log(a.length)

void

指定一个函数没有返回值

function foo():void 
    return undefined  // 允许void类型返回undefined

type FnType = ()=>void
function foo(fn:FnType):void 
    fn()
    return undefined  // 允许void类型返回undefined


// type FooType = (name:string)=>infoType[]
function foo(name:string): infoType[] 
    let info:infoType[] = []
    info.push(name:\'ss\',age:33)
    return info

never

表示的是那些永不存在的值的类型

// 返回never的函数必须存在无法达到的终点
function error(message: string): never 
    throw new Error(message);


// 推断的返回值类型为never
function fail() 
    return error("Something failed");


// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never 
    while (true) 
    

元组

已知元素数量和类型的数组,各元素的类型不必相同

数组类型应该是同一类型

// Declare a tuple type
let x: [string, number];
// Initialize it
x = [\'hello\', 10]; // OK
// Initialize it incorrectly
x = [10, \'hello\']; // Error

联合类型

联合成员,二个及以上

let s:string | number = \'\'

交叉类型

并集

let s:IPointType & IPointType2

类型别名

type 关键字

type MyType = number | string

function printID(id:MyType)
    console.log(id)

接口别名

interface 关键字

interface PointType 
    x: number
    y: number
    z?:number

// 可以多次声明
interface PointType 
    name: string

    
// 继承
interface PointType2 extends PointType
    age:number

function foo(point:PointType)
    

与type区别

  1. 在定义对象类型时,大部分情况都可使用
  2. type的使用范围更广,interface 只能声明对象
  3. interface 可以多次声明, type不允许相同的别名存在
  4. interface 支持继承

类型断言

const imgEl = document.querySelector(\'.img\') 
// 不确定imgEl 是什么对象时
 imgEL.src  // imgEl不是HTMLImageElement时报错

// 类型断言:确定类型时使用
const imgEl = document.querySelector(\'.img\')  as HTMLImageElement

as 关键字

断言规则:

  • 更加具体的类型
  • 不太具体类型: any 、unkown

非空类型断言:?!

info.obj?.name

info.obj!.name=\'xxx\' obj强制不为空,危险

字面量

const name:\'hyf\' | \'aa\' | \'3\' = \'3\'

调用签名

函数可被调用,并且有其他属性

与 type 定义的区别: type 不包含其他属性

interface ICallBack 
    name:string;
    age:number;
    (dir:string):string   // type xxx = (dir:string)=>string

const callback: ICallBack = (dir:string):string=>
    return dir

构造签名

class Person 
    

interface Iclass 
    new ():Person

函数的重载

// 函数重载签名
function foo(arg:number,arg2:number):number
function foo(arg:string,arg2:string):string

// 通用函数实现
function foo(arg:any,arg2:any):any
    return arg+arg2

this

默认是any类型

tsconfig.json

noImplicitThis: 是否允许模糊的this

内置工具

ThisParameterType

// 提取函数中this类型
type FooType = typeof foo

type FooThisType = ThisParameterType<FooType>

OmitThisParameter

过滤this

// 省略this,
type PureFooType = OmitThisParameter<FooType>

ThisType

绑定一个上下文的this

interface ISate 
	name:string


interface IState
	state:ISate
    eating:()=>void

// & ThisType<ISate> 绑定this 上下文
const store:IState & ThisType<ISate> 
	...
    eating()
    	console.log(this.name)
	

Partial

把一个对象中类型转为可选

interface IT
	name:string


//使用
type ITOption = Partial<IT>  // name?:string
    
    
// 实现
type HYPartial<T> = 
	[P in keyof T]?:T[P]

Required

把一个对象中类型转为必选

interface IT
	name?:string,
    age:number


//使用
type ITOption = Required<IT>  // name:string;age:number
// 实现
type HYRequired<T> = 
	[P in keyof T]-?:T[P]

Readonly

把一个对象中类型转为只读

interface IT
	name?:string,
    age:number


//使用
type ITOption = Readonly<IT>  // readonly name:string; readonly age:number
// 实现
type HYReadonly<T> = 
	readonly [P in keyof T]:T[P]

Record<keyType,valueType>


interface IT
	name?:string,
    age:number

type t1 = \'aaa\'|\'ddd\'|\'ccc\'
//使用
type ITOption = Record<t1,IT>   // key的类型必须是t1, value的类型必须是t2

const option:ITOption = 
    aaa:
        name:\'xxx\',
    	age:22
    ,
    ddd:
        age:22
    

type Res = keyof any // number|string|symbol
// 实现
type HYRecord<Keys extends keyof any,T> = 
	[P in keyof Keys]:T

  1. t1是一个联合类型
  2. 确保t1 是一个可以作为key的联合类型: <Keys extends keyof any,T>

Pick<Type,Keys>

挑选出 类型 组成新的类型

interface IT
	name?:string
    age:number
    height:number


// 选出age,height
type ITOption = Pick<IT,\'height\'|\'age\'>
    
// 实现
type HYPick<T,K extends keyof T> = 
	[P in K]:T[P]

Omit<Type,Keys>

过滤属性

interface IT
	name?:string
    age:number
    height:number


// 去除age,height
type ITOption = Pick<IT,\'height\'|\'age\'>  // name?:string
    
// 实现
type HYOmit<T,K extends keyof T> = 
    // 判断P 是否存在于 K中 存在 never 否则 返回对应P(属性)
	[P in keyof T as P extends K? never:P ]:T[P]

Exclude

联合类型中 排除掉

type MYType = \'aaa\' | \'bbb\' | \'ccc\'

type ITOption = Exclude<MYType,\'aaa\'>  // \'bbb\'|\'ccc\'

type HYExclude<T,E> = T extends E? never:T

Extract

联合类型中提取

type MYType = \'aaa\' | \'bbb\' | \'ccc\'

type ITOption = Extract<MYType,\'aaa\'|\'bbb\'>  // \'aaa\'|\'bbb\'

type HYExtract<T,E> = T extends E? T : never

NonNullable

排除所有null/undefined类型

type MYType = \'aaa\' | \'bbb\' | \'ccc\' | null | undefined

type ITOption = NonNullable<MYType>  // \'aaa\' | \'bbb\' | \'ccc\'

type HYNonNullable<T> = T extends null|undefined? never :T 

ReturnType

获取一个函数的返回值类型

// 获取一个函数的返回值类型
type CallFn = (arg1:number,arg2:number2) => number
function foo()
    return \'foo\'


type CallReturnType = ReturnType<CallFn>   // number
type FooReturnType = ReturnType<typeof foo>  // string
    
type HYReturnType<T> = 
// 必须是函数类型 限制类型  extends  (...args:any) => any
// 第二个extends表示  T 属于 xxx类型吗?
// 加上推断infer 
type HYReturnType<T extends (...args:any) => any > = T extends (...args:any) => infer R? R:never

InstanceType

所有构造函数的实例的类型

class Person1 
  constructor()

  


// 区别 typeof Person 和 Person
// typeof Person 构造函数具体类型
function factory<T extends new (...arg:any[])=>any>(ctor:T):T
  return new ctor()

const a = factory(Person) // function factory<typeof Person>(ctor: typeof Person): typeof Person

// InstanceType 构造函数创建出来实例对象的具体类型  Person
function factory2<T extends new (...arg:any[])=>any>(ctor:T):InstanceType<T>
  return new ctor()

const a1 = factory2(Person) // function factory<typeof Person>(ctor: typeof Person): Person


type HYInstanceType<T extends new (...args:any) => any > = T extends new (...args:any) => infer R? R:never

类的使用

class Person 
  // 严格模式下,需要初始化,可以使用name!:string的语法不初始化,
  name!: string  
  age: number
  constructor(name:string,age:number)
    this.name = name
    this.age = age
  

  eating()

  


// 语法糖 ,同名参数可以在construct函数中 在参数前加上修饰符表示
class Person 
  
  // name: string  
  // age: number
  constructor(public name:string, private age:number)
    this.name = name
    this.age = age
  

  eating()

  

public

公共的,默认就是public

private

私有的, 只在类的内部访问

protected

只在类及子类中使用,受保护的属性和方法

readonly

只读属性,不能写入

getter/setter

如果有私有属性需要给到外界,可以使用getter、setter

抽象类 abstract

abstract class Person 
  // 只声明没有实现体
  // 不能实例化
  // 抽象方法必须存在抽象类中
  abstract eating()


class Child1 extends Person 
  // 子类必须实现 eating
  eating()
    console.log(1)
  


class Child2 extends Person 
  // 子类必须实现 eating
  eating()
    console.log(2)
  


function foo(shap:Person)
  shap.eating()


foo(new Child1())
foo(new Child2())

索引签名

interface ICollection 
    // 索引签名, length需要和 index 返回值类型一致
	[index:number]:any;  // 通过数字类型 arr[0]访问
    [index2:string]:any;  // 可以通过字符串类型 obj[\'name\']
    length:number

泛型

将类型当做参数传入

function foo<T>(arg:T):T
  return arg


const res1 = foo<number>(123)

const res2 = foo<string>(\'aaa\')

const res3 = foo<name:string>(name:\'sss\')

// 省略写法
const res4 = foo(\'aaaaa\')  // 会自动进行类型推理

接口泛型

interface IFoo<T = string> 
  name:T;
  age:number


const foo:IFoo<string> = 
  name:\'xxx\',
  age:22


const foo2:IFoo<number> = 
  name:222,
  age:22


// 默认类型 string
const foo3:IFoo = 
  name:\'222\',
  age:22

泛型类的使用

class Person<T = string> 
  name:T
  age:T
  constructor(name:T,age:T) 
    // ...
  



const person  = new Person(\'123\',\'123\')

const person2  = new Person<number>(1,2)

泛型约束extends

不会丢失自身的类型属性

泛型参数约束

<O,T extends keyof O>

映射类型

只能使用type,不能使用interface

type MapPerson<T> = 
  [property in keyof T]:T[property]


interface Person
  name:\'sss0\';
  age:33


type PersonCopy = MapPerson<Person>

可选属性

type MapPerson<T> = 
  [property in keyof T]?:T[property]


interface Person
  name:\'sss0\';
  age:33


type PersonCopy = MapPerson<Person>

只读属性

type MapPerson<T> = 
  readonly [property in keyof T]?:T[property]


interface Person
  name:\'sss0\';
  age:33


type PersonCopy = MapPerson<Person>

+和-

默认修饰符前是+,

-?: 去掉? 必传

type MapPerson<T> = 
  +readonly [property in keyof T]-?:T[property]


interface Person
  name:\'sss0\';
  age:33


type PersonCopy = MapPerson<Person>

模块化

js 文件如果 有export 那么就被认为是一个模块

ts中 如果导入的类型,需要在类型前加 type 关键字

import type IPerson from \'./index.ts\'

命名空间

目前使用ES module

namespace xxx 
  export function foo()
    console.log(3)
  


export 
  xxx

.d.ts文件

只写类型的声明,告知typescript 有哪些类型

  • 内置类型声明
    +
  • 外部定义类型声明
  • 自定义类型声明

declare 类型声明

// 声明变量,可以让在ts中使用这些变量而不报错
declare const name:string
declare const age:number

// 声明函数
declare function foo(bar:string): string

// 声明类
declare class Person 
  constructor(public name:string,public age:number)



// 声明文件模块
declare module "*.png"
declare module "*.svg"
declare module "*.jpg"
declare module "*.jpeg"

// 声明模块
declare module MyAxios 
  export const method:string


// 命名空间 $.axios
declare namespace $ 
	export function axios(config:any): any

tsconfig配置

创建:

tsc --init

使用:

tsc [filename]   // 如果跟文件,会忽略当前的tsconfig.js的配置

配置选项:


    "compilerOptions": 
      "target": "ESNext", // 将代码编译为最新版本的 JS
      "useDefineForClassFields": true, // 使用 Object.defineProperty 定义 class 中的属性,而非使用 obj.key = value 的形式定义属性
      "module": "ESNext", // 使用 ES Module 格式打包编译后的文件
      "moduleResolution": "Node", // 使用 Node 的模块解析策略
      "strict": true, // 启用所用严格的类型检查
      "jsx": "preserve", // 保留原始的 JSX 代码,不进行编译
      "sourceMap": true, // 生成 sourceMap 文件
      "resolveJsonModule": true, // 允许引入 JSON 文件
      "isolatedModules": true, // 该属性要求所有文件都是 ES Module 模块。
      "esModuleInterop": true, // 允许使用 import 引入使用 export = 导出的内容
      "lib": ["ESNext", "DOM"], // 引入 ES 最新特性和 DOM 接口的类型定义
      "skipLibCheck": true // 跳过对 .d.ts 文件的类型检查
    ,
    files:[]  // 指定哪些ts文件需要编译,项目较小时适合
    include:[]  // 
	exclue:[],
	

条件类型

someType extends otherType ? TrueType: falseType  // 和 三元运算符类似

推断 infer

// 推断出类型,在true分支中返回
someType extends infer R ? R: never

分发类型

type toArray<T> = T extends any?T[]:never

type newType = toArray<number|string>  // 如果传入的是联合类型会进行分发 string[]|number[]

typescript TypeScript基础知识

/*
  Types:
  Many people do not realize it, but JavaScript does in fact have types, they're just "Duck
  Typed", which roughly means that the developer does not have to think about them.
  
  JavaScript's types also exist in TypeScript:
   boolean: (true/false)
   number: integers, floats, Infinity , and NaN
   string: characters, and strings of characters
   []: Arrays of other types, like number[] or boolean[]
   {}: Object literal
   undefined: not set
   
  TypeScript also adds
   enum: enumerations like { Red, Blue, Green }
   any: use any type
   void: nothing
*/

// Primitive type example:
  let isDone: boolean = false;
  let height: number = 6;
  let name: string = "bob";
  let list: number[] = [1, 2, 3];
  let list: Array<number> = [1, 2, 3];
  enum Color {Red, Green, Blue};
  let c: Color = Color.Green;
  let notSure: any = 4;
  notSure = "maybe a string instead";
  notSure = false;
  
  function showMessage(data: string): void {
    alert(data);
  }
  showMessage('hello');

// optional parameters using ?
  function logMessage(message: string, isDebug?: boolean)
  {
    if (isDebug) {
    console.log('Debug: ' + message);
    } else {
    console.log(message);
    }
  }

/*Typescript classes
  TypeScript also treats classes as their own type
*/

  class Foo { foo: number; }
  class Bar { bar: string; }
  class Baz {
    constructor(foo: Foo, bar: Bar) { }
  }

/*Interfaces
  Sometimes classes are "more" than a developer wants. Classes end up creating code, in the
  form of transpiled ES2015 classes, or transpiled ES5 constructor functions.
  
  Interfaces are abstract descriptions of things. Interfaces can be used to represent any non-primitive
  JavaScript object. Interfaces   are literally "abstract" in the sense that they produce no code,
  ES2015, or ES5. Interfaces exist only to describe types to tsc.
*/

// Here is an example of an interface describing an Object literal:
  interface Action {
    name: string;
  }
  
  let a: Action = {
    name: 'clean kitchen today'
  }

/* Shapes 
  Underneath TypeScript is JavaScript, and underneath JavaScript is typically a JIT (just in
  time compiler). Given JavaScript's underlying semantics, types are typically reasoned about
  by "shapes". These underlying "shapes" work like TypeScript's interfaces, and are in fact
  how TypeScript compares custom types like classes, and interfaces.
*/

// Consider an expansion of the previous example:
  interface Action {
    name: string;
  }
  let a: Action = {
    name: 'clean kitchen today'
  }
  class NotAnAction {
    name: string;
    constructor() {
      this.name = 'Constructor function (class)';
    }
  }
  a = new NotAnAction(); // valid TypeScript!

/*
  Despite the fact that Action, and NotAnAction have different identifiers, tsc lets us
  assign an instance of NotAnAction to 'a' which has a type of Action . This is because
  TypeScript only really cares that Objects have the same "shape". In other words if two
  objects have the same attributes, with the same typings, those two objects are considered to
  be of the same type.
*/

以上是关于TypeScript基础的主要内容,如果未能解决你的问题,请参考以下文章

typescript TypeScript基础知识

[TypeScript 基础系列] TypeScript 的安装以及编写第一个 TS 文件

TypeScript入门基础

TypeScript入门基础

带你了解Typescript的14个基础语法

TypeScript系列教程06基础类型