main.ts 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. /**
  2. *? 为什么用 TS
  3. ** 1 避免类型错误,编译期发现问题好过运行时出 bug
  4. ** 2 编辑器可以提供更好的代码提示,减少阅读文档查看接口实现的时间
  5. *
  6. */
  7. //? 类型系统
  8. //* 基本类型
  9. type allType = {
  10. readonly str: string
  11. strKey?: "STRING_KEY" | "NUMBER_KEY"
  12. num: number
  13. bint: bigint
  14. bool: boolean
  15. symbol: symbol
  16. null: null
  17. undefined: undefined
  18. obj?: object
  19. obj2?: Record<string, unknown>
  20. obj3?: { [k: string]: unknown }
  21. }
  22. const noTypeObj = {
  23. strKey: "STRING_KEY",
  24. str: "string",
  25. num: 123,
  26. bint: 12345678987654321n,
  27. bool: false,
  28. null: null,
  29. symbol: Symbol("symbol"),
  30. undefined: void 0,
  31. }
  32. const dataObj = noTypeObj as allType
  33. noTypeObj.str = "can change"
  34. dataObj.str = "can not change"
  35. //* 字面量类型
  36. {
  37. // number string boolean 类型可定义字面量类型
  38. type num = 1 | 2 | 4 | 8
  39. type key = "key" | "null"
  40. type TRUE = true | "true"
  41. let stringType = "str" // type string
  42. const str = "string" // type "string"
  43. type getDataParamsType = { type: "get" | "post" }
  44. const getData = ({ type }: getDataParamsType) => type
  45. getData({ type: "get" })
  46. const GET = { type: "get" } // as getDataParamsType
  47. getData(GET)
  48. }
  49. //* 联合类型 | 和 &
  50. {
  51. type requestType = "get" | "post" | "put" | "head"
  52. type requestType2 = "post" | "put" | "delete"
  53. type requestData = { url: string } & { method: requestType }
  54. type noop = 1 & 2
  55. type response = { data?: number | string | null }
  56. type commonType = Extract<requestType, requestType2> // 'post' | 'put'
  57. type withoutGet = Exclude<requestType, "get"> // "post" | "put" | "head"
  58. type notNullData = NonNullable<response["data"]> // number | string
  59. }
  60. //* 数组和对象
  61. {
  62. type strArr = Array<string>
  63. type numberArr = number[]
  64. type tuples = [number, string]
  65. const tuples: tuples = [1, "2"]
  66. type arrValType = strArr[number] // 数组元素类型
  67. type tuplesValType = tuples[1] // 元组元素类型
  68. type objMap = Record<string, tuples>
  69. type obj = {
  70. str: string
  71. [k: string]: string // 索引签名, 动态属性对象/
  72. }
  73. const obj: obj = {
  74. str: "1",
  75. newKey: "32",
  76. }
  77. type objStrType = obj["str"] // 取对象某一属性类型,不能使用 obj.str
  78. }
  79. //* enum
  80. {
  81. enum Color {
  82. red,
  83. blue = 2,
  84. }
  85. const ColorObj = {
  86. red: 0,
  87. blue: 2,
  88. 0: "red",
  89. 2: "blue",
  90. }
  91. const red: Color = Color.red
  92. const redStr = Color[Color.red] === "red"
  93. }
  94. //* 特殊类型
  95. {
  96. type evil = any // 跳过类型校验
  97. type oops = never // 不会发生
  98. type nothing = void // 没有
  99. type whatsThis = unknown // 未知类型
  100. /**
  101. * any
  102. * 尽量避免使用,依赖的 js 模块为提供类型声明时使用,便于快速集成
  103. * 多数情况可使用 unknow 或范型来处理
  104. *
  105. * never
  106. * bottom type, 所有类型的子类型,不能被任何其他类型赋值
  107. * 表示不会发生的,如永远抛出异常或不会终止的函数.
  108. *
  109. * void
  110. * 空值,多用于没有 return 的函数返回值声明
  111. *
  112. * unknown
  113. * top type,任何类型都是其子类型,可以被任何类型赋值
  114. */
  115. const makeError = (msg: string): never => {
  116. throw new Error(msg)
  117. }
  118. const forever = (): never => {
  119. while (true) {}
  120. }
  121. const noArg = (a: never) => {}
  122. noArg(1)
  123. const nothing = (): void => {
  124. // do nothing
  125. }
  126. const und: void = undefined
  127. const getType = (data: unknown) => typeof data
  128. getType("string")
  129. getType(123)
  130. }
  131. //* 函数
  132. {
  133. // 类型定义
  134. type isBoss = (id: string, name: number) => boolean
  135. type getName = {
  136. (id: string, name: string): string
  137. (userInfo: userInfo): string
  138. }
  139. interface getUserName {
  140. (id: string): string
  141. }
  142. // 类型标注
  143. const getId = (user: userInfo): string => user.id
  144. // 重载
  145. {
  146. const getName: getName = getUserName
  147. getName("id", "张小黑")
  148. getName({ id: "2", name: "李二狗" })
  149. function getUserName(userId: string, userName: string): string
  150. function getUserName(userInfo: userInfo): string
  151. function getUserName(idOrInfo: string | userInfo, name?: string) {
  152. if (typeof idOrInfo === "string") return name
  153. return idOrInfo.name
  154. }
  155. getUserName("id", "王大柱")
  156. getUserName({ id: "3", name: "刘二黑" })
  157. }
  158. // this
  159. type createdFn = (this: { data: string }, val: number, key: string) => string
  160. const created: createdFn = function () {
  161. return this.data.trim()
  162. }
  163. const data: ThisParameterType<createdFn> = { data: "data" }
  164. const params: Parameters<createdFn> = [1, "key"]
  165. const returnStr: ReturnType<createdFn> = "string"
  166. }
  167. //* 范型
  168. {
  169. const toArray = <T>(one: T, two: T): T[] => [one, two]
  170. toArray(1, 3)
  171. toArray("2", "6")
  172. }
  173. //* type vs interface
  174. {
  175. // 1 声明
  176. type userInfo = {
  177. name: string
  178. }
  179. interface userInfoInterface {
  180. name: string
  181. }
  182. // 扩展
  183. type withAge = userInfo & { age: number }
  184. interface userInfoInterface {
  185. age: number
  186. }
  187. // 2. 继承及实现
  188. interface topUser extends userInfoInterface {
  189. index: number
  190. }
  191. class powerUser implements userInfoInterface {
  192. name: string
  193. age: number
  194. constructor({ age, name }: withAge) {
  195. this.age = age
  196. this.name = name
  197. }
  198. }
  199. }
  200. //* 工具类型
  201. {
  202. /**
  203. ** 内置类型
  204. *
  205. * Partial<Type> 对象属性转为可选属性
  206. * Readonly<Type> 对象属性转为制度属性
  207. * Record<Keys,Type>
  208. * Pick<Type, Keys> 挑选部分属性组成新的类型
  209. * Omit<Type, Keys> 移除部分属性组成新的类型
  210. * Exclude<Type, ExcludedUnion> 联合类型中移除某些类型
  211. * Extract<Type, Union> 取两个类型交集
  212. * NonNullable<Type> 不为空值的类型,等同于 Exclude<Type,null | undefined>
  213. * Parameters<Type> 函数的参数类型
  214. * ConstructorParameters<Type> 构建函数的参数类型
  215. * ReturnType<Type> 函数返回值类型
  216. * InstanceType<Type> Class 的示例类型
  217. * Required<Type> 对象属性转为必选属性
  218. * ThisParameterType<Type> 函数 this 类型
  219. * OmitThisParameter<Type> 移除函数 this 定义后的函数类型
  220. * ThisType<Type> 定义指向当前对象的 this 类型
  221. *
  222. ** utility-types 社区工具类型库
  223. * https://github.com/piotrwitek/utility-types
  224. *
  225. **/
  226. // 自定义工具类型
  227. type awaited<T> = T extends Promise<infer R> ? R : T
  228. const promiseStr = Promise.resolve(["string"]) // type Promise<string[]>
  229. type awaitedType = awaited<typeof promiseStr> // type string[]
  230. const value: awaitedType = ["str"]
  231. }
  232. //? 应用
  233. //* switch 类型覆盖检查
  234. {
  235. // type requestType = "get" | "post" | "put"
  236. enum requestType {
  237. get,
  238. post,
  239. // put,
  240. }
  241. const noop = (n: never) => n
  242. const checkRequestType = (t: requestType): number => {
  243. switch (t) {
  244. case requestType.get:
  245. return t + 1
  246. case requestType.post:
  247. return t + 2
  248. default:
  249. return noop(t)
  250. }
  251. }
  252. }
  253. //* 对象 增删改查
  254. {
  255. //* typeof 取类型推断出的类型, keyof 取对象中所有 key 的集合
  256. type keyofDataObj = keyof typeof dataObj
  257. type allTypekey = keyof allType
  258. const assign = <O>(obj: O) => Object.assign({}, dataObj, obj)
  259. // get
  260. const _getDataByKey = (key: allTypekey) => dataObj[key]
  261. const getDataByKey = <K extends allTypekey>(key: K) => dataObj[key]
  262. const allValue = _getDataByKey("strKey") // type 所有的可能 value
  263. const dataStrKey = getDataByKey("strKey") // type "STRING_KEY" | "NUMBER_KEY" | undefined
  264. // add
  265. const addDataKey = <O>(obj: O) => assign(obj)
  266. const newData = { newKey: 678 }
  267. addDataKey(newData).newKey // type number
  268. // const addKey = (key, val) => assign({ [key]: val }) ??
  269. // merge
  270. const mergeAllTypeObj = (obj: Partial<allType>) => assign(obj)
  271. mergeAllTypeObj({ bint: 321n, strKey: "STRING_KEY" })
  272. // set
  273. type setVal = <K extends allTypekey>(key: K, val: allType[K]) => allType
  274. const setAllTypeVal: setVal = (key, val) => assign({ [key]: val })
  275. setAllTypeVal("strKey", "STRING_KEY")
  276. setAllTypeVal("null", null)
  277. //del
  278. const delDataOfKey = <K extends allTypekey>(key: K)/* : Omit<allType, "num"> */=> {
  279. const newData = { ...dataObj }
  280. delete newData[key]
  281. return newData
  282. }
  283. const withoutNum = delDataOfKey("num")
  284. withoutNum.num // 类型推断不满足需补充类型声明
  285. }
  286. //* axios 网络请求
  287. import axios from "axios"
  288. export interface userInfo {
  289. id: string
  290. name: string
  291. age?: number
  292. }
  293. {
  294. interface pageList<T> {
  295. list: T[]
  296. total: number
  297. }
  298. const getUserList = (page: string) =>
  299. axios.get<pageList<userInfo>>("/user", { params: { page } })
  300. const userCompontent = {
  301. data: {
  302. list: [] as userInfo[],
  303. total: 0,
  304. },
  305. async getUserList(page: string) {
  306. const res = await getUserList(page)
  307. this.data.list = res.data.list
  308. this.data.total = res.data.total
  309. },
  310. }
  311. }
  312. //* js 中的类型定义
  313. import { getUserInfoWithType, getUserInfo } from "./user.js"
  314. {
  315. ;async () => {
  316. const infoRes = await getUserInfoWithType(123)
  317. infoRes
  318. const notypeRes = await getUserInfo("id")
  319. notypeRes
  320. }
  321. }
  322. //? 总结
  323. /**
  324. ** 不要用 any
  325. ** 不要依赖类型推断,关键方法及暴露到外部的接口需定义参数及返回值类型
  326. ** 使用最“小”的类型
  327. **/