>source

TypesScript에서 제네릭을 구현하는 방법을 이해하는 데 문제가 있습니다. 비슷한 질문이 많이 있다는 것을 알고 있지만 내 사용 사례를 다루는 것 같지는 않습니다. (있다이 질문, 그러나 다른 우려가 있습니다. 즉, 함수의 출력이 함수의 입력과 동일한 유형이라는 것입니다)

제네릭이 두 가지 유형으로 제한되는 이와 같은 기능을 갖고 싶습니다.출력은 입력과 동일한 유형입니다.:

const increase = <T extends string | number>(
  param: T,
): T => {
    if (typeof param === "number") {
        // Here typescript should know that param can only be a number
        return param + 1;
    }
    // Here TypeScript should know that param can only be a string
    return "one more " + param;
};
const stringResult = increase("apple"); // "one more apple"
// Here TypeScript should know that stringResult is a string
const numResult = increase(2); // 3
// Here TypeScript should know that numResult is a number

그러나 다음과 같은 오류가 발생합니다.

Type 'number' is not assignable to type 'T'.
  'number' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'string | number'.

하지만 유형 확인을했습니다. if 위의 진술, T 이어야합니다 number 그리고 string | number .

내가 원하는 것이 TypeScript에서 가능합니까? 그렇다면 내가 뭘 잘못하고 있니?

  • 답변 # 1

    화살표 함수가 될 함수가 필요하지 않은 경우 함수를 쉽게 오버로드 할 수 있습니다.

    function increase(param: string): string;
    function increase(param: number): number;
    function increase(param: string | number): string | number {
        if (typeof param === "number") {
            // Here typescript should know that param can only be a number
            return param + 1;
        }
        // Here TypeScript should know that param can only be a string
        return "one more " + param;
    }
    const stringResult = increase("apple"); // "one more apple"
    // Here TypeScript should know that stringResult is a string
    const numResult = increase(2); // 3
    // Here TypeScript should know that numResult is a number
    
    

    놀이터 링크

    또한 매개 변수 유형에 따른 동작의 차이를 자세히 설명하는 개별 Intellisense를 제공 ​​할 수 있습니다.

    화살표 함수가 될 함수가 절대적으로 필요한 경우 화살표 함수를 오버로드하는 방법에 대한이 답변을 참조하십시오.

    JavaScript에는 유형이 없기 때문에 진정한 함수 오버로딩을 제공 할 수 없습니다. 이를 해결하기 위해 TypeScript를 사용하면 오버로딩을 표현하는 추가 함수 서명을 제공 할 수 있습니다. 함수의 실제 구현은 매개 변수 유형을 수동으로 구별하고 적절한 동작을 선택해야합니다. TypeScript 핸드북도 참조하십시오.

  • 답변 # 2

    예, 당신이 발견했듯이 TypeScript 컴파일러는 프로그램을 통해 각 경로를 따르고 이런 방식으로 유형을 확인하기에 충분히 정교하지 않습니다. 인덱싱 된 유형은 문제에 대한 해결책이 될 수 있지만 아직 사용 사례에 충분히 유연하지 않습니다.

    이를 엄격하게 수행 할 수있는 방법이 있지만, 모자를 붙잡 으십시오. 방문자 패턴과 같은 일부 취향에는 약간의 Java 스타일 일 수 있습니다.

    기본적으로 가능한 각 입력 유형을 클래스에 래핑하여 모두 공유 인터페이스를 구현하면 방문자 개체를 작성하여 유형별로 필요한 기능을 수행 할 수 있으며 컴파일러는 방문자 개체가 완전히 해당 공유 인터페이스를 구현하는 모든 클래스에 대한 형식화 된 기능. 그리고 아니 if 또는 switch 그래서 밥 삼촌의 불만은 없습니다.

    다음과 같이 보일 수 있습니다.

    interface Increase<T> {
        value: T
        accept(visitor: IncreaseVisitor): T
    }
    class NumIncrease implements Increase<number>{
        constructor(public value: number) {}
        accept(visitor: IncreaseVisitor): number {
            return visitor.visitNum(this)
        }
    }
    class StrIncrease implements Increase<string>{
        constructor(public value: string) {}
        accept(visitor: IncreaseVisitor): string {
            return visitor.visitStr(this)
        }
    }
    interface IncreaseVisitor {
        visitNum(numIncrease: Increase<number>): number
        visitStr(strIncrease: Increase<string>): string
    }
    const oneMoreVisitor: IncreaseVisitor = {
        visitNum: (numIncrease: Increase<number>) => numIncrease.value + 1,
        visitStr: (strIncrease: Increase<string>) => "one more " + strIncrease.value
    }
    function increase <T>(param: Increase<T>): T {
        return param.accept( oneMoreVisitor )
    }
    const stringResult = increase(new StrIncrease("apple"))
    console.log(stringResult) // "one more apple"
    // Now TypeScript *does* know that stringResult is a string
    const numResult = increase(new NumIncrease(2))
    console.log(numResult) // 3
    // Now TypeScript *does* know that numResult is a number
    
    

  • 답변 # 3

    언급했듯이 : output of the function is the same type as the input of the function

    Typescript 문서를 기반으로 : type argument inference — 컴파일러는 다음 값을 설정합니다. T 우리가 전달하는 인수의 유형에 따라 자동으로 Typescript 문서

    function increase<T>(
      param: T,
    ){
        if (typeof param === "number") {
            // Here typescript should know that param can only be a number
            return param + 1;
        }
        // Here TypeScript should know that param can only be a string
        return "one more " + param;
    };
    const stringResult = increase("apple"); // "one more apple"
    // Here TypeScript should know that stringResult is a string
    const numResult = increase(2); // 3
    
    

관련 자료

  • 이전 php - 유효성 검사 후 후크가 양식 페이지로 리디렉션되지 않음
  • 다음 php : Laravel의 큐 작업 내에서 Symfony Process 함수를 실행하는 방법