大綱
本章主要是一些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,它的作用是將傳入的屬性變為必選項:
- 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框架為主,過段時間會陸續上傳,如果對大家有幫助記得點個贊~ , 如有錯誤請指正, 我們一起解決,一起進步。