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