| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import assert from 'node:assert'; const functions = { add: (a: number, b: number) => a + b, pow: (a: number) => a * a, twice: (a: string) => a + a, } as const; type FunctionId = keyof typeof functions; type GetFunction<T extends FunctionId> = typeof functions[T]; function runFunction<Id extends FunctionId>( id: Id, ...parameters: Parameters<GetFunction<Id>> ): ReturnType<GetFunction<Id>> { const f = functions[id]; return f(...parameters); } assert(runFunction('add', 1, 2) === 3); assert(runFunction('pow', 6) === 36); assert(runFunction('twice', 'hello ') === 'hello hello '); |
runFunction은 정해진 함수 키랑 인자로 또 다른 함수를 호출하는 함수임.
함수 호출은 타입 문제가 없는데 f(...parameters) 이부분에서 문제가 있음
f의 타입이 유니언 타입으로 추론돼서 그런거같음
이런 함수를 만들 방법이 있을까 any 이런거 안쓰고
오류는 아래처럼 나옴
Type 'string | number' is not assignable to type 'ReturnType<GetFunction<Id>>'.
Type 'string' is not assignable to type 'ReturnType<GetFunction<Id>>'.ts(2322)
Type 'string' is not assignable to type 'ReturnType<GetFunction<Id>>'.ts(2322)
A spread argument must either have a tuple type or be passed to a rest parameter.ts(2556)
f에다 타입힌트를 줘보지
어케할지를 모르겠음
const f: GetFunction<Id>
마찬가지임
ts는 잘 모르겠지만 id 복잡하게 할거 없이 그냥 string아님?
runFunction 호출하면서 타입 체킹이랑 파라미터 힌트 얻는게 주 목적이라서 그럼. 'add' 입력하면 뒤에 인자가 알아서 number, number로 지정하도록 바뀌고 'twice' 입력하면 string 받도록 됨
그냥 string으로 하면 되긴하는데 없는 키를 넣어도 컴파일 타임에 못잡아줌
ts가 컴파일타임에만 돌아가는 녀석이라면 안될거 같은데
Parameters는 Id로 생성된거지만 Parameters는 id의 값에 따라 변하는 놈이 아님. 이게 되려면 parameters의 타입에 id가 들어갈 수 있어야하는데, ts에서 제네릭 인자로 값은 못넣는듯
그럼 내가 하려는건 몬하는건가 걍?
내 생각엔 그럼 ㅇㅇ
keyof 로 뽑은 키를 제네릭으로 들고다니면서 원래 객체 타입의 인덱스로 접근하면 타입이 온전하게 보존됨
멋지네 index만 알아서 타입을 알 수 있나 싶었는데 딱 그런게 있었구나
https://www.typescriptlang.org/docs/handbook/2/keyof-types.html