大綱
本章主要是一些ts的類型工具以及模塊化和相關實踐,涉及以下內容:
- 類型編程
- module和namespace
- 小技巧
- ts在react中的實踐
這篇稍微有點零碎,建議多查閱文檔或者查閱相關的文章進行更多的了解,代碼示例以告知 QAQ
往期推薦:
類型編程
- 索引類型(假定我們要取出如下對象的name屬性對應的值)
const user = {
name: 'lili',
age: 20,
sex: 'woman',
}
// 聲明類型
interface User {
[key: string]: any
}
function choose(obj: User, key: string[]): any[] {
return key.map(item => obj[item]) // 返回對應屬性的值 返回的是數組
}
choose(user, ['name'])
- 索引類型查詢操作符
class Person1 {
public name: string = 'lili'
public age: number = 20
}
type getTypePerson = keyof Person1
interface Point {
x: number;
y: number;
}
// type keys = "x" | "y"
type keys = keyof Point;
- 索引訪問操作符 T[K][], 之前也提到過
function Person2<T, K extends keyof T>(obj: T, name: K[]): T[K][] {
return name.map(item => obj[item])
}
const User2 = { name: 'lili', age: 20}
Person2(User2, ['name', 'age'])
// 以下是代碼提示: (相對更加嚴謹)
// (local function) Person2<{
// name: string;
// age: number;
// }, "name" | "age">(obj: {
// name: string;
// age: number;
// }, name: ("name" | "age")[]): (string | number)[]
- 映射類型 [K in keyof T]
interface User3interface {
name: string,
age: number,
}
// 添加每個都為可選類型
type User3<T> = {
[K in keyof T]?: T[K]
}
type User3s = User3<User3interface>
// 代碼提示:
// type User3s = {
// name?: string | undefined;
// age?: number | undefined;
// }
- 截獲函數返回值類型 ---- ReturnType
interface User4Interface {
name: string,
age: number,
}
type UserType = () => User4Interface
type User4 = ReturnType<UserType> // User4Interface
- 類型遞歸
interface Other {
hobby: string,
sex: string,
}
interface User5 {
name: string,
age: number,
other: Other
}
// 為每個類型添加一個可選類型
// 1. 類型工具 Partial
type U1 = Partial<User5>
// 代碼提示:
// type U1 = {
// name?: string | undefined;
// age?: number | undefined;
// other?: Other | undefined;
// }
// 2. 手動實現
type Particals<T> = {
[U in keyof T]?: T[U] extends object ? Particals<T[U]> : T[U]
}
type U2 = Particals<User5>
// type U2 = {
// name?: string | undefined;
// age?: number | undefined;
// other?: Particals<Other> | undefined;
// }
- 工具類型
’+‘號 ’-‘號 這兩個關鍵字用于映射類型中給屬性添加修飾符,比如-?就代表將可選屬性變為必選,-readonly代表將只讀屬性變為非只讀。比如TS就內置了一個類型工具Required<T>,它的作用是將傳入的屬性變為必選項:
- Required 將傳入的屬性變為必選項
type Required<T> = { [P in keyof T]-?: T[P] };
- Exclude 的作用是從 T 中排除出可分配給 U的元素. T extends U指T是否可分配給U
type Exclude<T, U> = T extends U ? never : T;
type T = Exclude<1 | 2, 1 | 3> // -> 2
- Omit
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>
type Foo = Omit<{name: string, age: number}, 'name'> // -> { age: number }
- Merge Merge<O1, O2>的作用是將兩個對象的屬性合并:
// type Merge<Obj1, obj2> = Compute<A> + Omit<U, T>
// type obj3 = Merge<obj1, obj2>
type obj1 = {
name: string,
age: number
}
type obj2 = {
sex: string,
hobby?: string,
}
type Compute<A extends any> =
A extends Function
? A
: { [K in keyof A]: A[K] }
type obj3 = Compute<obj1 & obj2>
// type obj3 = {
// name: string;
// age: number;
// sex: string;
// hobby?: string | undefined;
// }
- Intersection Intersection是Extract與Pick的結合,Intersection<T, U> = Extract<T, U> + Pick<T, U>
type obj4 = {
name: string,
age: number,
}
type obj5 = {
name: string,
sex: string,
}
type Intersection<T extends object, U extends object> = Pick<T, Extract<keyof T, keyof U> & Extract<keyof U, keyof T>> // Extract 提取
type obj6 = Intersection<obj4, obj5>
// type obj6 = {
// name: string;
// }
- Overwrite<T, U>顧名思義,是用U的屬性覆蓋T的相同屬性.
type obj7 = {
name: string,
age: number,
}
type obj8 = {
name: number,
}
// import { Diff } from 'utility-types' 要安裝一下庫
type Overwrite<T extends object, U extends object, I = Diff<T, U> & Intersection<U, T>> = Pick<I, keyof I>
type obj9 = Overwrite<obj7, obj8>
// type obj9 = {
// name: number; --- 被重寫了
// age: number;
// }
// Mutable 將 T 的所有屬性的 readonly 移除
type Mutable<T> = {
-readonly [P in keyof T]: T[P]
}
type ob = {
readonly name: string,
age: number,
}
type obj10 = Mutable<ob>
// type obj10 = {
// name: string;
// age: number;
// }
module和namespace
全局變量
比如在1.ts定義:const a = 1, 2.ts定義: const a = 2 這樣全局中定義的變量會報錯 因為重復聲明了 避免全局變量導出類型
export type User = {
name: string,
age: number,
}
- 導出多個類型
// 導出多個類型
type User1 = {
name: string,
age: number,
}
interface User2 {
name: string,
age: number,
}
// "isolatedModules": false, tsconfig.json 要設置一下
export { User1, User2 }
- 重命名
export { User1 as user1 }
- 引入
import { User2 as user2 } from './module';
// 整體導入
import * as u from './module';
// 同樣的 --- 默認導出
export default () => {
}
- namespace
其實一個命名空間本質上一個對象,它的作用是將一系列相關的全局變量組織到一個對象的屬性
如果一個命名空間在一個單獨的 TypeScript 文件中,則應使用三斜杠 /// 引用它,語法格式如下:
// index.ts
// 聲明全局的明明空間
declare namespace USER {
// 導出接口
export interface find { (name: string): string }
export interface create { (name: string): string }
export interface update { (name: string): string }
export interface deleted { (name: string): string }
}
// 引入文件
/// <reference path = "index.ts" />
// 使用命名空間的模塊
interface API {
USER: {
update: USER.update
// .....
},
}
小技巧
- 注釋,利于智能提示快速定位代碼
interface User {
/**
* 用戶
*/
name: string,
age: number,
}
const user: User = { name: 'lili', age: 20 }
// 以下是代碼提示
// (property) User.name: string
// 用戶
- 類型推導
function getUser(name: string): string {
return name
}
// typeof 獲取整體函數的類型
type getU = typeof getUser
// type getU = (name: string) => string
// h獲取返回值的類型
type returnT = ReturnType<typeof getUser>
// type returnT = string
- 巧用Omit
有時候我們需要復用一個類型,但是又不需要此類型內的全部屬性,因此需要剔除某些屬性,這個時候 Omit 就派上用場了。
interface User1 {
name: string,
age: number,
sex: string,
}
type newUser1 = Omit<User1, 'sex'>
// type newUser1 = {
// name: string;
// age: number;
// }
- Record 高級類型
Record 允許從 Union 類型中創建新類型,Union 類型中的值用作新類型的屬性。有利于類型安全
type List = 'u1' | 'u2' | 'u3'
// 要求用戶表的屬性必須包含 { name: string, age: number } 類型字段
type UserList = Record<List, { name: string, age: number }>
const userList: UserList = {
u1: { name: 'lili', age: 20 },
u2: { name: 'xiaoming', age: 21 },
u3: { name: 'xiaohong', age: 22 },
}
react實踐
- 編寫一個無狀態的組件
寫法1:
// 定義一個接口
interface Rrop {
/**
* 這是一個react組件的屬性
*/
name: string,
age: number,
}
// 無狀態組件
export const comp: React.SFC<Rrop> = props => {
const { name, age } = props
return (
<div>name: {name} age: {age}</div>
)
}
寫法2:
type Props1 = {
click(e: React.MouseEvent<HTMLElement>): void
children?: React.ReactNode
}
const handleClick = () => console.log('click')
const Events = ({ click: handleClick}: Props1) => {
<div onClick={handleClick}></div>
}
- 編寫狀態組件
避免狀態被顯示改變 所以 需要賦 readonly
const initialState = {
name: 'lili',
age: 20
}
type States = Readonly<typeof initialState>
export class InitialComp extends React.Component {
// 再次只讀
public readonly state: States = initialState
render() {
return (
<div>hello</div>
)
}
}
- ref
interface Props {
name: string,
age: number,
}
interface State {
name: string,
}
export class StateComp extends React.Component<Props, State> {
private inputRef = React.createRef<HTMLInputElement>() // 創建ref div 組件的話那么這個類型就是 HTMLDivElement。
constructor(props: Props) {
super(props)
this.state = { // (property) React.Component<Props, State, any>.state: Readonly<State> 組件自動為我們分配的
name: 'lili'
}
}
private setStat(val: string) {
this.setState({ name: val })
}
// onChange事件
private onChangeInput(e: React.ChangeEvent<HTMLInputElement>) {
this.setState({ name: e.target.value })
}
// form表單事件
private handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault()
}
render() {
return (
<>
<div>{this.state.name}</div>
<input ref={this.inputRef} onChange={e => this.onChangeInput(e)}/>
</>
)
}
}
- 默認屬性傳遞
interface Other {
hobby? : string
}
class ClassProp {
public name: string = ''
public submit = (name: string): string => name
public other: Other = {
hobby: ''
}
}
// 實例化類傳遞 默認屬性
export class PropsClass extends React.Component<ClassProp, State> {
// 1. 可以減少代碼量
// 2. 減少出錯率
public static defaultProps = new ClassProp()
public render() {
const { name, other } = this.props
// 如果遇到屬性找不到可以三木運算符判斷下或者是 other!.hobby
return (
<div>{ name } { other.hobby}</div>
)
}
}
- promise類型問題
// promise類型問題
interface propP<T> {
name: string,
age: number,
classes: T,
}
export class PromiseComp extends React.Component {
// 返回promise對象類型
public async getData(name: string): Promise<propP<string[]>> { // 表示返回的res的參數類型
return {
name: 'lili',
age: 20,
classes: ['class1','clas2'],
}
}
public request() {
this.getData('lili').then(res => {
console.log(res)
})
}
}
到此,系列文章基本完結啦~ 近期也在整理一些 ts 實踐性的文章,主要以react框架為主,過段時間會陸續上傳,如果對大家有幫助記得點個贊~ , 如有錯誤請指正, 我們一起解決,一起進步。