Skip to content

Item 51: Avoid Unnecessary Type Parameters

要点

  • Avoid adding type parameters to functions and classes that don't need them.
  • Since type parameters relate types, every type parameter must appear two or more times to establish a relationship.
  • Remember that a type parameter may appear in an inferred type.
  • Avoid "return-only generics."
  • Unneeded type parameters can often be replaced with the unknown type.
  • 避免给不需要类型参数的函数和类添加类型参数。
  • 由于类型参数关联类型,因此每个类型参数必须至少出现两次或更多次以建立关系。
  • 记住,类型参数可能出现在推断类型中。
  • 避免“仅返回类型的泛型”。
  • 不必要的类型参数通常可以用 unknown 类型替代。

正文

ts
function identity<T>(arg: T): T {
  return arg
}

💻 playground


ts
const date = identity(new Date())
//    ^? const date: Date
const nums = [1, 2, 3]
//    ^? const nums: number[]
const numsCopy = nums.map(identity)
//    ^? const numsCopy: number[]

💻 playground


ts
function identity<T>(arg: T): T {
  //           (decl.)    1   2
  return arg
}

💻 playground


ts
function third<A, B, C>(a: A, b: B, c: C): C {
  return c
}

💻 playground


ts
function third<C>(a: unknown, b: unknown, c: C): C {
  return c
}

💻 playground


ts
declare function parseYAML<T>(input: string): T

💻 playground


ts
interface Weight {
  pounds: number
  ounces: number
}

const w: Weight = parseYAML('')

💻 playground


ts
declare function parseYAML<T = null>(input: string): T
const w: Weight = parseYAML('') // still allowed

💻 playground


ts
declare function parseYAML(input: string): unknown

💻 playground


ts
const w = parseYAML('') as Weight

💻 playground


ts
function printProperty<T, K extends keyof T>(obj: T, key: K) {
  console.log(obj[key])
}

💻 playground


ts
function printProperty<T>(obj: T, key: keyof T) {
  console.log(obj[key])
}

💻 playground


ts
function getProperty<T, K extends keyof T>(obj: T, key: K) {
  return obj[key]
}

💻 playground


ts
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key]
}

💻 playground


ts
class ClassyArray<T> {
  arr: T[]
  constructor(arr: T[]) {
    this.arr = arr
  }

  get(): T[] {
    return this.arr
  }
  add(item: T) {
    this.arr.push(item)
  }
  remove(item: T) {
    this.arr = this.arr.filter((el) => el !== item)
  }
}

💻 playground


ts
class Joiner<T extends string | number> {
  join(els: T[]) {
    return els.map((el) => String(el)).join(',')
  }
}

💻 playground


ts
class Joiner {
  join<T extends string | number>(els: T[]) {
    return els.map((el) => String(el)).join(',')
  }
}

💻 playground


ts
class Joiner {
  join(els: (string | number)[]) {
    return els.map((el) => String(el)).join(',')
  }
}

💻 playground


ts
function join(els: (string | number)[]) {
  return els.map((el) => String(el)).join(',')
}

💻 playground


ts
interface Lengthy {
  length: number
}
function getLength<T extends Lengthy>(x: T) {
  return x.length
}

💻 playground


ts
function getLength(x: Lengthy) {
  return x.length
}

💻 playground


ts
function getLength(x: { length: number }) {
  return x.length
}

💻 playground


ts
function getLength(x: ArrayLike<unknown>) {
  return x.length
}

💻 playground


ts
declare function processUnrelatedTypes<A, B>(a: A, b: B): void

💻 playground


ts
declare function processUnrelatedTypes(a: unknown, b: unknown): void

💻 playground


ts
function processUnrelatedTypes<A, B>(a: A, b: B) {
  a = b
  //  ~ Type 'B' is not assignable to type 'A'.
  b = a
  //  ~ Type 'A' is not assignable to type 'B'.
}

💻 playground


ts
function processUnrelatedTypes(a: unknown, b: unknown) {
  a = b // ok
  b = a // ok
}

💻 playground

Released under the MIT License.