조건부 유형에 값을 어떻게 할당합니까?
나는 첫 번째 매개 변수가되도록 함수를 작성하기 위해 노력하고있어 boolean
,이 인수가 있는지 여부에 따라 true
또는 false
, 두 번째 인수 중 하나 받아들이는 함수 string
또는 string[]
.
내 시도는 다음과 같습니다.
type P<B extends boolean> = B extends true ? string[] : string
function callback<B extends boolean>(b: B, t: (f: P<B>) => void) {
const file = 'file'
if (b) {
t([file]) // <-- Error: Argument of type 'string' is not assignable to parameter of type 'P<B>'.
} else {
t(file) // <-- Error: Argument of type 'string[]' is not assignable to parameter of type 'P<B>'.
}
}
callback(false, (f: string) => {}) // <-- No problem, resolves the correct argument type
callback(true, (f: string[]) => {}) // <-- No problem, resolves the correct argument type
이것은 함수가 호출 될 때 올바른 인수 유형을 해결하기 위해 작동합니다. 그러나 함수 내부에서 TS 컴파일러는 조건부 유형을 string
또는로 확인할 수 없다는 오류를 표시합니다 string[]
. 이를 수행하는 올바른 방법은 무엇입니까?
놀이터 링크 .
답변
다음은 두 매개 변수가있는 객체를 전달하여 수행하는 한 가지 방법입니다. true
하나의 서명 또는 false
다른 서명 이있는 형식을 사용 하여 컴파일러는 b
속성 을 테스트하여 개체를 구별 할 수 있습니다 .
type f = { b: false, t: (f: string) => void };
type t = { b: true, t: (f: string[]) => void };
type fOrT = f | t;
function callback(x: fOrT) {
const file = 'file'
if (x.b) {
x.t([file])
} else {
x.t(file)
}
}
callback({ b: false, t: (f: string) => {} })
callback({ b: true, t: (f: string[]) => {} })
TypeScript 플레이 그라운드
예를 들어 사용자 정의 입력을 작성하여 다른 변수를 기반으로 유형을 좁힐 수 있습니다.
function instanceOfMyTYpe(textArray: string[] | string, flag: boolean): textArray is string {
return flag;
}
let file = "test" as string | string[];
file.toUpperCase(); // doesn't work. Property 'toUpperCase' does not exist on type 'string | string[]'.
if (instanceOfMyTYpe(file, true)) file.toUpperCase(); // but this works
else file.forEach((text)=>text.toUpperCase()); // and so does this
한 변수를 다른 변수와 연결하지 않으므로 잘못된 함수 호출이 계속 발생할 수 있습니다. 예를 들어 배열과 참 플래그를 사용하여 함수를 호출하면주의하지 않아도 프로그램이 배열이 실제로 문자열이라고 생각하게됩니다.
이와 같은 일반 유형 인수를 사용하는 것은 목에 정말 고통 스럽습니다. 이것이 정확히 어떻게 작동하는지 확실하지 않지만 typescript가 유형을 좁힐 수는 거의 없습니다. 구성 t
내부로 마우스를 가져 if
가면 유형 (f: P<B>) => void
이 (f: string) => void
있거나 없는 것을 볼 수 있습니다 (f: string[]) => void
. 또는 : 다른 변수에 따라 한 변수의 유형을 좁힐 수 없었습니다. 나는 이것이 한계라고 생각하고 지금은 이것을 고칠 방법을 생각할 수 없습니다. 내가 틀렸을 수도 있지만, 이전에 좀 더 복잡한 맥락에서이 상황에 직면했고 작동하도록 기능의 디자인을 변경해야했습니다.
난 그냥 할 수있는이 경우에 생각 t([file] as any)
하고 t(file as any)
, 마지막으로, 이러한 유형의 포인트는 올바른 방법으로 호출하는 기능을 강제하는 것입니다. 올바르게 호출되면 내부에서 무엇을해야하는지 알고 any
있습니다. 여기에 몇 개의 s를 추가 할 가치가 있다고 생각합니다 .
또한 오버로드를 사용하여 제네릭을 제거 할 수 있지만 문제가 해결되지는 않습니다.
function callback(b: true, t: (f: string[]) => void): void
function callback(b: false, t: (f: string) => void): void
function callback(b: boolean, t: ((f: string) => void)) | ((f: string[]) => void)) {
//
}
실제로 any
s가 필요하지 않은 한 가지 해결책은 객체를 사용하는 것이지만 응용 프로그램에서 다른 논리를 변경해야 할 수도 있으므로 이상적이지 않습니다.
type Options = {
b: true
t: (f: string[]) => void
} | {
b: false
t: (f: string) => void
}
function callback(options: Options) {
const file = 'file'
if(options.b) options.t([file])
else options.t(file)