TypeScript - Learning TypeScript Chap. 10 Generics

이소라·2023년 4월 27일
0

TypeScript

목록 보기
24/28

Chapter 10. Generics

  • 때로는 코드에서 호출되는 방식에 따라 다양한 타입으로 작동하도록 의도할 수 있습니다.

    • 매개변수로 모든 타입을 허용한다면, 매개변수 타입과 함수 반환 타입 간의 관계를 말할 수 있는 방법이 필요합니다.
    • TypeScript는 제네릭(generic)을 사용해 타입 간의 관계를 알아냅니다.
  • TypeScript에서 함수와 같은 구조체는 제네릭 타입 매개변수를 원하는 수만큼 선언할 수 있습니다.

    • 제네릭 타입 매개변수는 제네릭 구조체의 각 사용법에 따라 타입이 결정됩니다.
    • 타입 매개변수는 구조체의 각 인스턴스에 대해 타입 인수라고 하는 서로 다른 타입을 함께 제공할 수 있지만, 타입 인수가 제공된 인스턴스 내에서는 일관성을 유지합니다.
    • 타입 매개변수는 전형적으로 T나 U 같은 단일 문자 이름 또는 Key와 Value 같은 파스칼 케이스 이름을 갖습니다.
  • 제네릭 구조체에서는 <, >를 사용해 someFunction<T> 또는 SomeInterface<T>처럼 제네릭을 선언합니다.



10.1 Generic Functions

  • 매개변수 괄호 앞에 홑화살표괄호(<, >)로 묶인 타입 매개변수에 별칭을 배치해 함수를 제네릭으로 만듭니다.
    • 해당 타입 매개변수를 함수 본문 내부의 매개변수 type annotation, 반환 type annotation, type annotation에서 사용할 수 있습니다.
function identity<T>(input: T) {
  return input;
}

// 타입 : 'me'
const stringy = identity('me');
// 타입 : 123
const numeric = identity(123);
  • 화살표 함수의 제네릭 선언은 매개변수 목록 바로 전인 ( 앞에 위치합니다.
const identity = <T>(input: T) => input;

// 타입 : 123
identity(123);
  • 이런 방식으로 함수에 타입 매개변수를 추가하면 타입 안전성을 유지하고 any 타입을 피하면서 다른 입력과 함께 재사용할 수 있습니다.

10.1.1 Explicit Generic Call Types

  • 제네릭 함수를 호출할 때 대부분의 TypeScript는 함수가 호출되는 방식에 따라 타입 인수를 유추합니다.
  • 타입 인수를 알 수 없는 제네릭 구문이 다른 제네릭 구문에 제공 된 경우, TypeScript에 알려줘야 하는 함수 호출 정보가 충분하지 않을 수 있습니다.
function logWrapper<Input>(callback: (input: Input) => void) {
  return (input: Input) => {
    console.log('Input:', input);
    callback(input);
  };
}

// 타입 : (input: string) => void
logWrapper((input: string) => {
  console.log(input.length);
});

// 타입 : (input: unknown) => void
logWrapper((input) => {
  // Error: Property 'length' does not exist on 'unknown'
  console.log(input.length);
});
  • 기본값이 unknown으로 설정되는 것을 피하기 위해 TypeScript에 해당 타입 인수가 무엇인지 명시적으로 알려주는 명시적 제네릭 타입 인수를 사용해 함수를 호출할 수 있습니다.
    • 명시적 제네릭 타입 인수는 이름<Type>와 같이 지정합니다.
    • TypeScript는 매개변수가 타입 인수로 제공된 것과 일치하는지 확인하기 위해 제네릭 호출에서 타입 검사를 수행합니다.
// 타입 : (input: string) => void
logWrapper<string>((input) => {
  console.log(input.length);
});

// Error: Argument of type '(input: boolean) => void' is not assignable 
// to paramter of type '(input: string => void'
//	Type of paramters 'input' and 'input' are incompatible
//		Type 'string' is not assignable to type 'boolean'
logWrapper<string>((input: boolean) => {
  console.log(input.length);
});

10.1.2 Multiple Function Type Parameters

  • 임의의 수의 타입 매개변수를 쉼표로 구분해 함수를 정의합니다.
  • 제네릭 함수의 각 호출은 각 타입 매개변수에 대한 자체 값 집합을 인수로 받습니다.
function makeTuple<First, Second>(first: First, second: Second) {
  return [first, second] as const;
}

// 타입 : readonly [boolean, string]
let tuple = makeTuple(true, 'abc');
  • 함수가 여러 개의 매개변수를 선언하면 해당 함수에 대한 호출은 명시적으로 제네릭 타입을 모두 선언하지 않거나 모두 선언해야 합니다.
    • TypeScript는 아직 제네릭 호출 중 일부 타입만을 유추하지는 못합니다.
function makePair<Key, Value>(key: Key, value: Value) {
  return {key, value};
}

// Ok, 타입 인수가 둘 다 제공되지 않음
// 타입 : {key: string, value: number }
makePair('abc', 123)

// Ok, 2개의 타입 인수가 제공됨
// 타입 : {key: string, value: number }
makePair<string, number>('abc', 123);
// 타입 : {key: 'abc', value: 123 }
makePair<'abc', 123>('abc', 123);

// Error: Expected 2 type arguments, but got 1
makePair<string>('abc', 123);
  • 제네릭 구조체에서 2개 이상의 타입 매개변수를 사용하는 것을 권장하지 않습니다.
    • 런타임 함수 매개변수처럼 많이 사용할수록 코드를 읽고 이해하는 것이 점점 어려워지기 때문입니다.



10.2 Generic Interfaces

  • interface도 제네릭으로 선언할 수 있습니다.
    • 제네릭 interface는 함수와 유사한 제네릭 규칙에 따릅니다.
    • 제네릭 interface는 interface 이름 뒤 <> 사이에 선언된 임의의 수의 타입 매개변수를 갖습니다.
    • 해당 제네릭 타입은 멤버 타입과 같이 선언의 다른 곳에서 사용할 수 있습니다.
interface Box<T> {
  inside: T;
}

let stringyBox: Box<string> = {
  inside: 'abc',
};

let numberBox: Box<number> = {
  inside: 123,
};

let incorrectBox: Box<number> = {
  // Error: Type 'boolean' is not assignable to type 'number'
  inside: false,
};
  • TypeScript에서 내장 Array 메서드는 제네릭 interface로 정의됩니다.
    • Array는 타입 매개변수 T를 사용해 벼열 안에 저장된 데이터의 타입을 나타냅니다.
interface Array<T> {
  // pop : 배열에서 마지막 요소를 제거하고 그 요소를 반환하는 메서드, 빈 배열일 경우 undefined를 반환함
  pop(): T | undefined;
  // push: 배열 끝에 새로운 요소를 추가하고 배열의 길이를 반환하는 메서드
  // @param items 배열에 추가된 새로운 요소
  push(...items: T[]): number;
}

10.2.1 Inferred Generic Interface Types

  • 제네릭 함수와 마찬가지로 제네릭 interface의 타입 인수는 사용법에서 유추할 수 있습니다.
    • TypeScript는 제네릭 타입을 취하는 것으로 선언된 위치에 제공된 값의 타입에서 타입 인수를 유합니다.
interface LinkedNode<Value> {
  next?: LinkedNode<Value>;
  value: Value;
}

function getLast<Value>(node: LinkedNode<Value>): Value {
  return node.next ? getLast(node.next) : node.value;
}

// 유추된 Value 타입 인수 : Date
let lastDate = getLast({
  value: new Date('09-13-1993')
})


// 유추된 Value 타입 인수 : string
let lastFruit = getLast({
  next: {
    value: 'banana'
  },
  value: 'apple'
});

let lastMismatch = getLast({
  next: {
    value: 123
  },
  // Error: Type 'boolean' is not assignable to type 'number'
  value: false
});
  • interface가 타입 매개변수를 선언하는 경우, 해당 interface를 참조하는 모든 type annotation이 이에 상응하는 타입 인수를 제공해야 합니다.
interface CrateLike<T> {
  contents: T;
}

// Error: Generic type 'CrateLike<T>' requires 1 type argument(s)
let missingGeneric: CrateLike = {
  inside: '??'
}



10.3 Generic Classes

  • 클래스도 나중에 멤버에서 사용할 임의의 수의 타입 매개변수를 선언할 수 있습니다.
  • 클래스의 각 인스턴스는 타입 매개변수로 각자 다른 타입 인수 집합을 가집니다.
class Secret<Key, Value> {
  key: Key;
  value: Value;
  
  constructor(key: Key, value: Value) {
    this.key = Key;
    this.value = Value;
  }
  
  getValue(key: Key): Value | undefined {
    reeturn this.key === key ? this.value : undefined;
  }
}

// 타입 : Secret<string, number>
const storage = new Secret(12345, 'luggage');
// 타입 : string | undefined
storage.getValue(1987);

10.3.1 Explicit Generic Class Types

  • 제네릭 클래스 인스턴스화는 타입 인수 유추 규칙을 따릅니다.
    • 함수 생성자에 전달된 매개변수의 타입으로부터 타입 인수를 유추할 수 있다면 TypeScript는 유추된 타입을 사용합니다.
    • 하지만 생성자에 전달된 인수에서 클래스 타입 인수를 유추할 수 없느 경우에는 타입 인수의 기본값은 unknown이 됩니다.
class CurriedCallback<Input> {
  #callback: (input: Input) => void;
  
  constructor(callback: (input: Input) => void) {
    this.#callback = (input: Input) => {
      console.log('Input:', input);
      callback(input);
  	};
  }
  
  call(input: Input) {
    this.#callback(input);
  }
}

// 타입 : CurriedCallback<string>
new CurriedCallback((input: string) => {
  console.log(input.length);
});

// 타입 : CurriedCallback<unknown>
new CurriedCallback((input) => {
  // Error: Property 'length' does not exist on tyep 'unknown'
  console.log(input.length);
});
  • 클래스 인스턴스는 명시적 타입 인수를 제공하여 기본값이 unknown이 되는 것을 피할 수 있습니다.
// 타입 : CurriedCallback<string>
new CurriedCallback<string>((input) => {
  console.log(input.length);
});


new CurriedCallback<string>((input: boolean) => {
  // Error: Argument of type '(input: boolean) => void' is not assinable 
  // to parameter of type '(input: string) => void'
  // 	Type of parameters 'input' and 'input' are incompatible
  //		Type 'string' is not assignable to type 'boolean'
  console.log(input.length);
});

10.3.2 Extending Generic Classes

  • 제네릭 클래스는 extends 키워드 다음에 오는 기본 클래스로 사용할 수 있습니다.
  • TypeScript는 사용법에서 기본 클래스에 대한 타입 인수를 유추하지 않습니다.
    • 기본값이 없는 모든 타입 인수는 명시적 type annotation을 사용해 지정해야 합니다.
class Quote<T> {
  lines: T;
  
  constructor(lines: T) {
    this.lines = lines;
  }
}

class SpokenQuote extends Quote<string[]> {
  speak() {
    console.log(this.lines.join('\n'));
  }
}

// 타입 : string
new Quote('The only real fear is the failure to try.').lines;
// 타입 : number[]
new Quote([4, 5, 6, 7, 8, 9]).lines;
// 타입 : string[]
new SpokenQuote([
  'Greed is so destructive', 
  'It destroys everything'
]).lines;

// Error: Argument of type 'number' is not assignable to parameter of type 'string'
new SpokenQuote([1, 2, 3, 4, 5]).lines;

10.3.3 Implementing Generic Interfaces

  • 제네릭 클래스는 모든 필요한 매개변수를 제공함으로써 제네릭 interface를 구현합니다.
  • 제네릭 interface는 제네릭 기본 클래스를 확장하는 것과 유사하게 작동합니다.
    • 기본 interface의 모든 타입 매개변수는 클래스에 선언되어야 합니다.
interface ActingCredit<Role> {
  role: Role;
}

class MoviePart implements ActingCredit<string> {
  role: string;
  speaking: boolean;
  
  constructor(role: string, speaking: boolean) {
    this.role = role;
    this.speaking = speaking;
  }
}

const part = new MoviePart('Miranda Priestly', true);
// 타입 : string
part.role;

class IncorrectExtension implements ActingCredit<string> {
  // Error: Property 'role' in type 'IncorrectExtension' is not assignable to the same property in base type 'ActingCredit<string>'.
  //	Type 'boolean' is not assignable to type 'string'.
  role: boolean;
}

10.3.4 Method Generics

  • 클래스 메서드는 클래스 인스턴스와 별개로 자체 제네릭 타입으로 선언할 수 있습니다.
    • 제네릭 클래스 메서드에 대한 각각의 호출은 각 타입의 매개변수에 대한 다른 타입 인수를 갖습니다.
class CreatePairFactory<Key> {
  key: Key;
  
  constructor(key: Key) {
    this.key = key;
  }
  
  createPair<Value>(value: Value) {
    return {key: this.key, value };
  }
}

// 타입 : createPairFactory<string>
const factory = new CreatePairFactory('role');
// 타입 : { key: string, value: number }
const numberPair = factory.createPair(10);
// 타입 : { key: string, value: string }
const stringPair = factory.createPair('Sophie');

10.3.5 Static Class Generics

  • 클래스의 정적(static) 멤버는 인스턴스 멤버와 구별되고 클래스의 특정 인스턴스와 연결되어 있지 않습니다.
    • 클래스의 정적 멤버는 클래스 인스턴스에 접근할 수 없거나 타입 정보를 지정할 수 없습니다.
    • 정적 클래스 메서드는 자체 타입 매개변수를 선언할 수 있지만, 클래스에 선언된 어떤 타입 매개변수에도 접근할 수 없습니다.
class BothLogger<OnInstance> {
  instanceLog(value: OnInstance) {
    console.log(value);
    return value;
  }
  
  static staticLog<OnStatic>(value: OnStatic) {
    // Error: Static members cannot reference class types arguments
    let fromInstance: OnInstance;
    
    console.log(value);
    return value;
  }
}

const logger = new BothLogger<number[]>;
// 타입 : number[]
logger.instanceLog([1, 2, 3]);
// 유추된 OnStatic 타입 인수 : boolean[]
BothLogger.staticLog([false, true]);
// 유추된 OnStatic 타입 인수 : string[]
BothLogger.staticLog(['abc', 'def']);



10.4 Generic Type Aliases

  • 타입 별칭(type alias)를 제네릭으로 선언할 수 있습니다.
    • 각 타입 별칭에는 T를 받는 Nullish 타입과 같은 임의의 수의 타입 매개변수가 주어집니다.
type Nullish<T> = T | null | undefined;
  • 제네릭 타입 별칭은 제네릭 함수의 타입을 설명하는 함수와 함께 사용됩니다.
type CreatesValue<Input, Output> = (input: Input) => Output;

// 타입 : (input: string) => number
let creator: CreatesValue<string, number>;

// Ok
creator = text => text.length;
// Error: Type 'string' is not assignable to type 'number'
creator = text => text.toUpperCase()

10.4.1 Generic Discriminated Unions

  • 판별된 union은 데이터의 성공적인 결과 또는 오류로 인한 실패를 나타내는 제네릭 결과 타입을 만들 때 사용할 수 있습니다.
type Result<Data> = FailureResult | SuccessfulResult<Data>;

interface FailureResult {
  error: Error;
  successed: false;
}

interface SuccessfulResult<Data> {
  data: Data;
  successed: true;
}

function handleResult(result: Result<string>) {
  if (result.successed) {
    // result : SuccessfulResult<string>
    console.log(`We did it! ${result.data}`);
  } else {
    // result : FailureResult
    console.log(`Awww....${result.error}`);
  }
  // Error: Property 'data' does not exist on type 'Result<string>'.
  //	Property 'data' does not exist on type 'FailureResult'
  result.data;
}



10.5 Generic Modifiers

  • TypeScript는 제네릭 타입 매개변수의 동작을 수정하는 구문도 제공합니다.

10.5.1 Generic Defaults

  • 타입 매개변수 선언 뒤에 =과 기본 타입을 배치해 타입 인수를 명시적으로 제공할 수 있습니다.
    • 기본값은 타입 인수가 명시적으로 선언되지 않고 유츄할 수 없는 모든 후속 타입에 사용됩니다.
interface Quote<T = string> {
  value: T;
}

let explicit: Quote<number> = { value: 123 };

let implicit: Qoute = { value: 'Be yourself. The world worships the original.' };
// Error: Type 'number' is not assignable to type 'string'
let mismatch: Qoute = { value: 123 };
  • 타입 매개변수는 동일한 선언 안의 앞선 타입 매개변수를 기본값으로 가질 수 있습니다.
    • 각 타입 매개변수는 선언에 대한 새로운 타입을 도입하므로 해당 선언 이후의 타입 매개변수에 대한 기본값으로 이를 사용할 수 있습니다.
interface KeyValuePair<Key, Value = Key> {
  key: Key;
  value: Value;
}

// 타입 : KeyValuePair<string, number>
let allExplicit: KeyValuePair<string, number> = {
  key: 'rating',
  value: 10,
};

// 타입 : KeyValuePair<string>
let allExplicit: KeyValuePair<string> = {
  key: 'rating',
  value: 'ten',
};

// Error: Generic type 'KeyValuePair<Key, Value>' requires between 1 and 2 type arguments.
let firstMissing: KeyValuePair = {
  key: 'rating',
  value: 10
};
  • 모든 기본 타입 매개변수는 선언 목록의 마지막에 와야 합니다.
    • 기본값이 없는 제네릭 타입은 기본값이 있는 제네릭 타입 뒤에 오면 안됩니다.
// Ok
function inTheEnd<First, Second, Third = number, Fourth = string>() {}
// Error: Required type parameters may not follow optional type parameters.
function inTheMiddle<First, Second = boolean, Third = number, Forth>() {}



10.6 Constrained Generic Types

  • TypeScript는 타입 매개변수가 제한된 타입에서만 작동해야 한다고 선언할 수 있으며, 이는 별칭 타입에만 허용됩니다.
    • 타입 매개변수를 제한하는 구문은 매개변수 이름 뒤에 extends 키워드를 배치하고 그 뒤에 이를 제한할 타입을 배치합니다.
interface WithLength {
  length: number;
}

function logWithLength<T extends WithLength>(input: T) {
  console.log(`length: ${input.length}`);
  return input;
}

// 타입 : string
logWithLength('No one can figure out your worth but you');
// 타입 : boolean[]
logWithLength([false, true]);
// 타입 : { length: 123 }
logWithLength({ length: 123 });

// Error: Argument of type 'Date' is not assignable to parameter of type 'WithLength'.
//  Property 'length' is missing in type 'Date' but required in type 'WithLength'.
logWithLength(new Date());

10.6.1 keyof and Constrained Type Parameters

  • keyof 연산자는 제한된 타입 매개변수와도 잘 작동합니다.
  • extendskeyof를 함께 사용하면 타입 매개변수를 이전 타입 매개변수의 키로 제한할 수 있습니다.
    • 이는 제네릭 타입의 키를 지정하는 유일한 방법입니다.
function get<T, Key extends keyof T>(container: T, key: Key) {
  return container[key];
}

const roles = {
  favorite: 'Fargo',
  others: ['Almost Famous', 'Burn After Reading', 'Nomadland'],
};

// 타입 : string
const favorite = get(roles, 'favorite');
// 타입 : string[]
const others = get(roles, 'others');

// Error: Arguments of type 'extras' is not assignable to parameter "'favorite' | 'others'"
const missing = get(roles, 'extras');
  • 타입 매개변수로 T만 제공되고 매개변수가 모든 keyof T일 수 있는 경우라면, 반환타입은 contatiner에 있는 모든 속성 값에 대한 union 타입이 됩니다.
    • 이렇게 구체적이지 않은 함수 선언은 각 호출이 타입 인수를 통해 특정 key를 가질 수 있음을 TypeScript에 나타낼 수 없습니다.
function get<T>(container: T, key: keyof T) {
  return container[key];
}

const roles = {
  favorite: 'Fargo',
  others: ['Almost Famous', 'Burn After Reading', 'Nomadland'],
};

// 타입 : string | string[]
const favorite = get(roles, 'favorite');
  • 제네릭 함수를 작성할 때 매개변수의 타입이 이전 매개변수 타입에 따라 달라질 수 있습니다.
    • 이러한 경우 올바른 매개변수 타입을 위해 제한된 타입 매개변수를 자주 사용하게 됩니다.



10.7 Promises

  • JavaScript의 Promise는 네트 워크 요청과 같이 요청 이후 결과를 받기까지 대기가 필요한 것을 나타냅니다.

    • 각 Pomise는 대기 중인 작업이 'resolve' 또는 'reject'하는 경우 콜백을 등록하기 위한 메서드를 제공합니다.
  • Promise는 TypeScript 타입 시스템에서 최종적으로 resolve된 값을 나타내는 단일 타입 매개변수를 가진 Promise 클래스로 표현됩니다.


10.7.1 Creating Promises

  • TypeScript에서 Promise 생성자는 단일 매개변수를 받도록 작성됩니다.
    • 해당 매개변수의 타입은 제네릭 Promise 클래스에 선언된 타입 매개변수에 의존합니다.
class PromiseLike<Value> {
  constructor(
  executor: (
   resolve: (value: Value) => void,
   reject: (reason: unknown) => void,
  ) => void
 ){ /* ... */}
}
  • 결과적으로 값을 resolve하려는 Promise를 만들려면 Promise의 타입 인수를 명시적으로 선언해야 합니다.
    • TypeScript는 명시적 제네릭 타입 인수가 없다면 기본적으로 매개변수 타입을 unknown으로 가정합니다.
    • Promise 생성자에 타입 인수를 명시적으로 제공하면 TypeScript가 결과로서 생기는 Promise 인스턴스의 resolve된 타입을 이해할 수 있습니다.
// 타입 : Promise<unknown>
const resolvesUnknown = new Promise((resolve) => {
  setTimeout(() => resolve('Done!', 1000));
});

// 타입 : Promise<string>
const resolvesString = new Promise<string>((resolve) => {
  setTimeout(() => resolve('Done!', 1000));
});
  • Promise의 제네릭 .then 메서드는 반환하는 Promise의 resolve된 값을 나타내는 새로운 타입 매개변수를 받습니다.
// 타입 : Promise<string>
const textEventually = new Promise<string>((resolve) => {
  setTimeout(() => resolve('Done!', 1000));
});
// 타입 : Promise<number>
const lengthEventually = textEventually.then((text) => text.length);

10.7.2 Async Functions

  • JavaScript에서 async 키워드를 사용해 선언한 모든 함수는 Promise를 반환합니다. JavaScript에서 async 함수에 따라서 반환된 값이 Thenable(.then() 메서드가 있는 객체, 거의 항상 Promise)이 아닌 경우, Promise.resolve가 호출된 것처럼 Promise로 래핑됩니다.
    • 그러므로 Promise를 명시적으로 언급하지 않더라도 aync 함수에서 수동으로 선언된 반환 타입은 항상 Promise 타입이 됩니다.
async function givesPromiseForString(): Promise<string> {
  return 'Done!';
}

// Error: The return type of an async function or method must be the global Promise<T> type
async function giveString() : string {
  return 'Done!';
}



10.8 Using Generics Right

  • 제네릭은 코드에서 타입을 설명하는데 많은 유연성을 제공할 수 있지만, 코드가 빠르게 복잡하 수 있습니다.
  • TypeScript의 모범 사례는 필요할 때만 제네릭을 사용하고, 제네릭을 사용할 때는 무엇을 사용을 위해 사용하는지 명확히 해야합니다.

10.8.1 The Golden Rule of Generics

  • 함수에 타입 매개변수가 필요한지 여부를 판단할 수 있는 간단하고 빠른 방법은 타입 매개변수가 최소 2번 이상 사용되었는지 확인하는 것입니다.
    • 제네릭은 타입 간의 관계를 설명하므로 제네릭 타입 매개변수가 한 곳에만 나타나면 여러 타입 간의 관계를 정의할 수 없습니다.
    • 따라서 각 함수 타입 매개변수는 매개변수에 사용되어야 하고, 그 다음 적어도 하나의 다른 매개변수 또는 함수의 반환 타입에서도 사용되어야 합니다.
// Bad
function logInput<Input extends string>(input: Input) {
  console.log('Hi', input);
}

// Good
function logInput(input: string) {
  console.log('Hi', input);
}

10.8.2 Generic Naming Conventions

  • 타입 매개변수에 대한 표준 명명 규칙은 기본적으로 첫 번째 타입 인수로 T를 사용하고, 후속 타입 매개변수가 존재하면 U, V 등을 사용하는 것입니다.
  • 타입 인수가 어떻게 사용되어야 하는지 맥락과 관련된 정보가 알려진 경우, 명명 규칙은 결우에 따라 해당 용어의 첫 글자를 사용하는 것으로 확장합니다.
    • 제네릭의 의도가 단일 문자 T에서 명확하지 않은 경우에는 타입이 사용되는 용도를 가리키는 설명적인 제네릭 타입 이름을 사용하는 것이 좋습니다.
// Bad
function labelBox<L, V>(l: L, v: V){ /* ... */ }

// Good
function labelBox<Label, Value>(l: Label, v: Value){ /* ... */ }
  • 구조체가 여러 개의 타입 매개변수를 갖거나 단일 타입 인수의 목적이 명확하지 않을 때마다 단일 문자 약어 대신 가독성을 위해 완전히 작성된 이름을 사용하는 것이 좋습니다.

0개의 댓글