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
}
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[]
ts
function identity<T>(arg: T): T {
// (decl.) 1 2
return arg
}
ts
function third<A, B, C>(a: A, b: B, c: C): C {
return c
}
ts
function third<C>(a: unknown, b: unknown, c: C): C {
return c
}
ts
declare function parseYAML<T>(input: string): T
ts
interface Weight {
pounds: number
ounces: number
}
const w: Weight = parseYAML('')
ts
declare function parseYAML<T = null>(input: string): T
const w: Weight = parseYAML('') // still allowed
ts
declare function parseYAML(input: string): unknown
ts
const w = parseYAML('') as Weight
ts
function printProperty<T, K extends keyof T>(obj: T, key: K) {
console.log(obj[key])
}
ts
function printProperty<T>(obj: T, key: keyof T) {
console.log(obj[key])
}
ts
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key]
}
ts
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key]
}
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)
}
}
ts
class Joiner<T extends string | number> {
join(els: T[]) {
return els.map((el) => String(el)).join(',')
}
}
ts
class Joiner {
join<T extends string | number>(els: T[]) {
return els.map((el) => String(el)).join(',')
}
}
ts
class Joiner {
join(els: (string | number)[]) {
return els.map((el) => String(el)).join(',')
}
}
ts
function join(els: (string | number)[]) {
return els.map((el) => String(el)).join(',')
}
ts
interface Lengthy {
length: number
}
function getLength<T extends Lengthy>(x: T) {
return x.length
}
ts
function getLength(x: Lengthy) {
return x.length
}
ts
function getLength(x: { length: number }) {
return x.length
}
ts
function getLength(x: ArrayLike<unknown>) {
return x.length
}
ts
declare function processUnrelatedTypes<A, B>(a: A, b: B): void
ts
declare function processUnrelatedTypes(a: unknown, b: unknown): void
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'.
}
ts
function processUnrelatedTypes(a: unknown, b: unknown) {
a = b // ok
b = a // ok
}