TypeScript에서 제네릭 배열을 어떻게 정의합니까?
다음과 같은 일반 인터페이스가 있다고 가정해 보겠습니다.
interface Transform<ArgType> {
transformer: (input: string, arg: ArgType) => string;
arg: ArgType;
}
그 다음에 이걸 여러 개 적용하고 싶습니다.Transform
아주string
이 배열을 어떻게 정의합니까?Transform
라는 것을 증명하는.<ArgType>
둘 다 동등합니다.Transform.transformer
그리고.Transform.arg
저는 다음과 같은 글을 쓰고 싶습니다.
function append(input: string, arg: string): string {
return input.concat(arg);
}
function repeat(input: string, arg: number): string {
return input.repeat(arg);
}
const transforms = [
{
transformer: append,
arg: " END"
},
{
transformer: repeat,
arg: 4
},
];
function applyTransforms(input: string, transforms: \*what type goes here?*\): string {
for (const transform of transforms) {
input = transform.transformer(input, transform.arg);
}
return input;
}
이 예에서는 어떤 유형을 정의합니까?const transforms
유형 시스템이 배열의 각 항목이 제네릭을 만족하는지 검증하기 위해 사용되는 것과 같습니다.Transform<ArgType>
인터페이스?
(다음의 TS 3.0 사용)
TypeScript가 직접적으로 실존적 유형을 지원했다면 사용하라고 말씀드리겠습니다.실존적 유형은 "내가 아는 것은 그 유형이 존재한다는 것뿐이지만, 그것이 무엇인지 모르거나 관심이 없다"와 같은 것을 의미합니다.그럼 당신의transforms
매개 변수의 유형은 다음과 같습니다.Array< exists A. Transform<A> >
의미는 "있는 것들의 배열"입니다.Transform<A>
어떤 사람들에게는 A
언어에서 이러한 유형을 허용하자는 제안이 있지만, 이를 지원하는 언어는 거의 없기 때문에 누가 알겠어요.
"포기"하고 그냥 사용할 수 있습니다.Array<Transform<any>>
이는 효과적이지만 다음과 같은 일관성 없는 사례를 포착하지는 못합니다.
applyTransforms("hey", [{transformer: repeat, arg: "oops"}]); // no error
하지만 당신이 말한 것처럼, 당신은 존재하는 유형이 없는 경우에도 일관성을 유지하려고 합니다.다행히도 다양한 수준의 복잡성을 가진 해결 방법이 있습니다.여기 하나 있습니다.
다음과 같은 형식 함수를 선언합니다.T
그리고 만약에Transform<A>
어떤 사람들에게는 A
그것은 돌아옵니다.unknown
(모든 값과 일치하는 새 최상위 유형...그렇게unknown & T
와 같음T
절대로T
), 그렇지 않으면 반환됩니다.never
(값이 일치하지 않는 맨 아래 유형...그렇게never & T
와 같음never
절대로T
):
type VerifyTransform<T> = unknown extends
(T extends { transformer: (input: string, arg: infer A) => string } ?
T extends { arg: A } ? never : unknown : unknown
) ? never : unknown
조건부 유형을 사용하여 이를 계산합니다.그 생각은 그것이 보는 것입니다.transformer
이해하기 위해A
그리고 나서 확인합니다.arg
그것과 호환됩니다.A
.
이제 입력할 수 있습니다.applyTransforms
일반적인 함수로서, 오직 a만 수용합니다.transforms
유형 요소가 있는 배열과 일치하는 매개 변수T
경기VerifyTransform<T>
:
function applyTransforms<T extends Transform<any>>(
input: string,
transforms: Array<T> & VerifyTransform<T>
): string {
for (const transform of transforms) {
input = transform.transformer(input, transform.arg);
}
return input;
}
작동하는 것을 확인할 수 있습니다.
applyTransforms("hey", transforms); // okay
일치하지 않는 내용을 전달하면 다음과 같은 오류가 발생합니다.
applyTransforms("hey", [{transformer: repeat, arg: "oops"}]); // error
이 오류는 특별히 밝지 않습니다. "[ts] Argument of type '{ transformer: (input: string, arg: number) => string; arg: string; }[]' is not assignable to parameter of type 'never'.
하지만 적어도 그건 오류야.
아니면, 당신이 하는 일이 단지 지나가는 것이라면arg
로.transformer
당신은 당신의 실존주의적인 것을 만들 수 있습니다.SomeTransform
다음과 같이 입력합니다.
interface SomeTransform {
transformerWithArg: (input: string) => string;
}
그리고 a를.SomeTransform
어느 쪽에서든지Transform<A>
원하는 항목:
const makeSome = <A>(transform: Transform<A>): SomeTransform => ({
transformerWithArg: (input: string) => transform.transformer(input, transform.arg)
});
그런 다음 일련의 작업을 수락합니다.SomeTransform
대신:
function applySomeTransforms(input: string, transforms: SomeTransform[]): string {
for (const someTransform of transforms) {
input = someTransform.transformerWithArg(input);
}
return input;
}
작동하는지 확인:
const someTransforms = [
makeSome({
transformer: append,
arg: " END"
}),
makeSome({
transformer: repeat,
arg: 4
}),
];
applySomeTransforms("h", someTransforms);
일관성이 없는 작업을 시도할 경우:
makeSome({transformer: repeat, arg: "oops"}); // error
은 더: "더합리적인발오생다니합가류다니▁you▁which발". "Types of parameters 'arg' and 'arg' are incompatible. Type 'string' is not assignable to type 'number'.
"
좋아요, 도움이 되길 바랍니다.행운을 빌어요.
TS 3.0에 추가된 일반 튜플레스트 파라미터를 사용하여 이 작업을 수행할 수 있습니다.
type TransformRest<T extends any[]> = {
[P in keyof T]: T[P] extends T[number] ? Transform<T[P]> : never
}
function applyTransforms<T extends any[]>(input: string, ...transforms: TransformRest<T>): string {
for (const transform of transforms) {
input = transform.transformer(input, transform.arg);
}
return input;
}
// Makes a tuple from it's arguments, otherwise typescript always types as array
function tuplify<TS extends any[]>(...args: TS) {
return args;
}
// Use like this:
const transforms = tuplify(
{
transformer: append,
arg: " END"
},
{
transformer: repeat,
arg: 4
},
);
//And call apply transforms like this:
applyTransforms("string", ...transforms)
//or like this:
applyTransforms("string", transform1, transform2)
설명.
타이프스크립트는 정말 강력한 유형 추론을 가지고 있지만, 보통 가능한 한 느슨한 유형을 선택합니다.이 경우에는 각 요소가 고유한 유형을 갖도록 변환을 튜플로 생각하도록 강제하고 추론이 나머지를 수행하도록 해야 합니다.
매핑된 유형으로 이 작업을 수행했습니다. 한 가지 문제는 Typescript가 숫자 키뿐만 아니라 모든 튜플 키(예: "길이")를 사용한다는 것입니다.숫자만 매핑하도록 강제하기만 하면 됩니다.따라서 조건은 다음과 같습니다.T[P] extends T[number]
언급URL : https://stackoverflow.com/questions/51879601/how-do-you-define-an-array-of-generics-in-typescript
'programing' 카테고리의 다른 글
원격 저장소에서 로컬 Git 분기를 삭제한 후 삭제 (0) | 2023.07.15 |
---|---|
빠른 로그 기준 2개의 상한 계산 (0) | 2023.07.15 |
상대 레이아웃의 백분율 너비 (0) | 2023.07.15 |
Springboot 1.X와 Springboot 2.0의 차이점 (0) | 2023.07.15 |
Git 및 GitHub의 기본 사항 이해 (0) | 2023.07.15 |