踩坑经验汇总
阅读前请先熟读阅读Typescript HandBook
使用 Typescript 一定要清楚哪些是运行时代码哪些是类型代码
类型
Type 别名
普通、简单类型声明一律使用type
与 interface 两者的关键区别是 type 不能被重复使用加入新属性,但 interface 可以一直扩展
// type 不支持 extends,使用 = 设置类型 export type MicroAppState = {
isError: boolean mounted: boolean loading: boolean resetting: boolean } // type 可以与其他type扩展出新类型 如 export type Result = {
context: {
warnings: HTMLElement[] references: HTMLElement[] elementsById: HTMLElement[] } } & OtherType
interface
复杂的、可扩展的、多重继承使用interface
interface Diagram {
// 构造函数可以这么写 constructor(options: anyType) } // interface的扩展使用extends关键字 interface BaseViewer extends Diagram {
// 构造函数也可以这么写 new (options: anyType) newMethod: () => void }
interface 没法实现 Utility type 如以下
type Person = {
name: string age: number } // 没有age的Person类型实现 const onlyNamePerson: Omit<Person, 'age'> = {
name: 'xaoMing' } // 没有名字和age的Person类型实现 const smPerson: Omit<Person, 'name' | 'age'> = {
}
any
Typescript 中使用做多的类型,任何不确定的类型都会用 any 表示
实际开发中我们尽量不实用 any,大量的使用 any 就没有必要使用 ts 开发了
// any会让下面的代码执行都成立 let obj: any = {
x: 0 } obj.foo() obj() obj.bar = 100 obj = 'hello' const n: number = obj
as
类型断言,就是告诉编译器我确定这家伙是这种类型
- as 断言
// as 语法 let someValue: unknown = 'this is a string' let strLength: number = (someValue as string).length
- 尖括号断言(无法与 jsx 配合使用)
let someValue: unknown = 'this is a string' let strLength: number = (<string>someValue).length
unknown
unknown 指的是不可预先定义的类型
unknown 的一个使用场景是,避免使用 any 作为函数的参数类型而导致的静态类型检查 bug
unknown 类型必须先转为一个确定类型后才能调用其属性或方法
return ( lang || (window as unknown as GLocaleWindow).g_locale || navigator.language )
void
返回类型,一个方法没有任何返回值时
// 一个接受字符串的不返回任何值的函数 type someMethod = (type: string) => void
never
返回类型,没法正常结束返回的类型
一般用在报错、死循环、switch 拖底中做返回类型,新手小白唔用
// throw error 返回值是never function foo(): never {
throw new Error('error message') } // 这个死循环的也会无法正常退出 function foo(): never {
while (true) {
} } // Error: 这个无法将返回值定义为never,因为无法在静态编译阶段直接识别出 function foo(): never {
let count = 1 while (count) {
count++ } } // Exhaustiveness checking 穷尽性检查 interface Triangle {
kind: 'triangle' sideLength: number } type Shape = Circle | Square | Triangle function getArea(shape: Shape) {
switch (shape.kind) {
case 'circle': return Math.PI * shape.radius 2 case 'square': return shape.sideLength 2 default: const _exhaustiveCheck: never = shape // Type 'Triangle' is not assignable to type 'never'. return _exhaustiveCheck } }
Literal Types
字面量类型, 使用了特定字符串或数字的类型
// let 和 const 声明的类型不同 // changingString的类型为 string; let changingString = 'Hello World' // constantString 的类型为 'Hello World'; const constantString = 'Hello World' // 无法通过编译 constantString = 'howdy'
字面量类型在处理字符串数字枚举值时很有效,但需要做转换来去掉类型问题
// 字面量类型无法识别两个GET字符串是相同的 const req = {
url: 'https://example.com', method: 'GET' } // 报错 Argument of type 'string' is not assignable to parameter of type '"GET" | "POST"'. handleRequest(req.url, req.method) // 修改方法1 使用 as 转换 const req = {
url: 'https://example.com', method: 'GET' as 'GET' } handleRequest(req.url, req.method as 'GET') // 修改方法2 使用 const 转换整个对象为字面量类型 const req = {
url: 'https://example.com', method: 'GET' } as const handleRequest(req.url, req.method)
操作符
?
可选变量
对象可不包含该 可选变量
interface PaintOptions {
shape: Shape xPos?: number yPos?: number } function paintShape(opts: PaintOptions) {
// ... } const shape = getShape() paintShape({
shape }) paintShape({
shape, xPos: 100 }) paintShape({
shape, yPos: 100 }) paintShape({
shape, xPos: 100, yPos: 100 })
可选参数
不传也不会报错
function f(x?: number) {
// ... } f() // OK f(10) // OK
!
非空断言操作符
function liveDangerously(x?: number | null) {
// 使用!告诉编译器我是真的 console.log(x!.toFixed()) }
keyof
keyof 可以获得一个类型所有的键并返回一个联合类型
type Person = {
name: string age: number } // PersonKey得到的类型为 'name' | 'age' type PersonKey = keyof Person // 使用案例 function getValue(p: Person, k: PersonKey) {
// 如果k不如此定义,则无法以p[k]的代码格式通过编译 return p[k] }
typeof
typeof 获取一个实际对象的类型
const me: Person = {
name: 'gzx', age: 16 } // { name: string, age: number | undefined } type P = typeof me // 可以通过编译 const you: typeof me = {
name: 'mabaoguo', age: 69 }
in
in 只能用在类型的定义中,可以对枚举类型进行遍历
// 这个类型可以将任何类型的键值转化成number类型 type TypeToNumber<T> = {
[key in keyof T]: number } const obj: TypeToNumber<Person> = {
name: 10, age: 10 }
泛型
泛型可以用在普通类型定义,类定义、函数定义上,如下:
// 普通类型定义 type Dog<T> = {
name: string; type: T } // 普通类型使用 const dog: Dog<number> = {
name: 'ww', type: 20 } // 类定义 class Cat<T> {
private type: T constructor(type: T) {
this.type = type } } // 类使用 const cat: Cat<number> = new Cat<number>(20) // 或简写 const cat = new Cat(20) // 函数定义 function swipe<T, U>(value: [T, U]): [U, T] {
return [value[1], value[0]] } // 函数使用 swipe<Cat<number>, Dog<number>>([cat, dog]) // 或简写 swipe([cat, dog])
泛型默认值
type Dog<T = string> = {
name: string; type: T } const dog: Dog = {
name: 'ww', type: 'hsq' }
泛型约束
在方法内需要调用泛型内的特定属性方法,需要使用 extends 执行泛型约束
interface Lengthwise {
length: number } function loggingIdentity<Type extends Lengthwise>(arg: Type): Type {
// 使用extends 继承自含有length的对象就不会报错了 console.log(arg.length) return arg }
泛型条件
高级玩法
Conditional Types
方法泛型
type off = <T, V>(events: T | string | string[], callback: V) => void
JSX 泛型
import {Select} from 'antd' export default (props) => { return <Select<string> {...props}> }
泛型工具
常用于表单提交,将已经定义好的类型抽像成表单提交的实际内容定义
// 将类型属性全部变为可选的 Partial<T> // 将类型属性全部变为必选的 Required<T> // 将 T 类型中的 K 键列表提取出来,生成新的子键值对类型。 Pick<T, K> const bird: Pick<Animal, "name" | "age"> = {
name: 'bird', age: 1 } // 在 T 类型中,去除 T 类型和 U 类型的交集,返回剩余的部分 Exclude<T, U> // 去除类型 T 中包含 K 的键值对 Omit<T, K> // 获取 T 类型(函数)对应的返回值类型 ReturnType<T>
用于声明普通对象
Record<K, T> type ELDrawerPropsType = {
onOk: (fieldsValue: Record<string, string>, index: number) => void; };
声明
声明文件
Typescript 中使用.d.ts
结尾的文件作为声明文件
声明文件应放置于项目跟路径的typings
目录内
delare
声明关键字,声明结果均为全局声明
// 全局声明变量 declare var declare let declare const // 全局声明方法 declare function // 全局声明类 declare class {
} // 全局声明枚举 declare enum // 全局声明类型 declare type // 全局声明接口 declare interface {
} // 全局声明命名空间 declare namespace // 全局声明模块 declare module
namespace
namespace 用来解决工程过大命名冲突的问题,可以跨文件使用
对外可通过 export 向外导出作为模块使用(deprecated)
// a.d.ts declare namespace FescoTechTao {
type A; } // b.d.ts declare namespace FescoTechTao {
type B; }
module
module 用来定义外部 ES 模块,可跨文件使用
// canvas.d.ts declare module 'diagram.js' {
export interface Canvas {
} } // eventBus.d.ts declare module 'diagram.js' {
export interface EventBus {
} } // main.ts import {
Canvas, EventBus } from 'diagram.js'
module 可以用来定义静态模块
declare module 'slash2' declare module '*.css' declare module '*.less' declare module '*.scss' declare module '*.sass' declare module '*.svg' declare module '*.png' declare module '*.jpg' declare module '*.jpeg' declare module '*.gif' declare module '*.bmp' declare module '*.tiff' declare module 'omit.js' declare module '*.xml' {
// Change this to an actual XML type const value: string export default value }
module 可以用来改写 npm 包中的模块定义
type PutResolveType = {
resolve: <A extends AnyAction>(action: A) => Promise<void> } type PutType = <A extends AnyAction>(action: A) => any declare module 'dva' {
export interface EffectsCommandMap {
put: PutResolveType & PutType call: Function select: Function take: Function cancel: Function [key: string]: any } }
module 可以补充声明没有编写声明文件的 npm 包
declare module 'dva-model-extend' declare module 'bpmn-js-properties-panel' declare module 'bpmn-js-properties-panel/lib/provider/camunda' declare module 'camunda-bpmn-moddle' declare module 'camunda-bpmn-moddle/resources/camunda'
module 可以扩展其他全局对象的属性方法
declare global {
interface Window {
ga: ( command: 'send', hitType: 'event' | 'pageview', fieldsObject: GAFieldsObject | string ) => void reloadAuthorized: () => void bpmnInstances: BpmnInstancesType } interface Console {
logModel: (namespace: string, expand?: boolean) => void logModelState: (namespace: string, expand?: boolean) => void } } declare module NodeJS {
interface Global {
host: string href: string _cookies: string _navigatorLang: string } }
使用 module 给 vue 扩展原型链
import type {
AxiosInstance } from 'axios' declare module 'Vue/types/vue' {
interface Vue {
$axios: AxiosInstance } }
/// 三斜线指令
///<reference types=“UMDModuleName/globalName” />
ts 早期模块化的标签, 用来导入依赖, ES6 广泛使用后, 在编写 TS 文件中不推荐使用,使用 import 代替
版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/typescriptbc/1182.html