유형 스크립트에서 고유한 항목으로 배열 유형을 정의하는 방법이 있습니까?
유형은 배열에 중복 항목이 있는지 감지하고 유형 스크립트에 오류를 발생시켜야 합니까?
type UniqueArray = [
// How to implement this?
]
const a:UniqueArray = [1, 2, 3] // success
const b:UniqueArray = [1, 2, 2] // error
PS: 현재 JS를 사용하여 중복 항목을 제거하고 있습니다만, 사전에 타이프스크립트 유형을 사용하여 이 오류를 캡처할 수 있는지 궁금합니다.
컴파일 시 이 방법이 가능한 유일한 방법은 배열이 리터럴로 구성된 튜플인 경우입니다.예를 들어, TypeScript에서 런타임 값은 같지만 유형이 다른 배열은 다음과 같습니다.
const tupleOfLiterals: [1, 2, 2] = [1, 2, 2];
const tupleOfNonLiterals: [number, number, number] = [1, 2, 2];
const arrayOfLiterals: (1 | 2)[] = [1, 2, 2];
const arrayOfNonLiterals: number[] = [1, 2, 2];
const constAssertedReadOnlyTupleOfLiterals = [1, 2, 2] as const;
첫 번째 사람만 당신이 원하는 대로 행동할 겁니다컴파일러는 그것을 깨달을 것입니다.tupleOfLiterals에는 정확히 3개의 요소가 있으며, 그 중 2개는 동일한 유형입니다.다른 모든 경우에 컴파일러는 무슨 일이 일어나고 있는지 이해하지 못합니다.때 함수나 수 , 는 따서어를통경다우 API에있이어한레와 같은 입니다.number[]그러면 대답은 "아니오, 당신은 이것을 할 수 없습니다."입니다.
만약 당신이 (아마도 주장을 통해) 리터럴의 튜플을 얻고 있다면...예를 들어, 당신의 코드를 라이브러리로 사용하는 개발자로부터, 당신은 작동하는 무언가를 얻을 기회가 있지만, 그것은 복잡하고 아마도 깨지기 쉽습니다.다음과 같은 방법이 있습니다.
먼저 TypeScript에는 없는 잘못된 유형처럼 동작하는 것이 나타납니다.이 아이디어는 값을 할당할 수 없는 유형(예: )이지만 컴파일러가 오류 메시지를 발견할 때 사용자 지정 오류 메시지를 생성합니다.다음은 완벽하지는 않지만 눈을 가늘게 뜨고 보면 타당한 오류 메시지가 표시됩니다.
type Invalid<T> = Error & { __errorMessage: T };
이제 우리가 대표합니다.UniqueArray콘크리트 타입으로 할 수 없습니다(그래서 no.const a: UniqueArray = ...하지만 도우미 함수에 전달하는 일반적인 제약 조건으로 나타낼 수 있습니다.어쨌든, 여기.AsUniqueArray<A>은 후보 유형인 후보배유형사용다니합을 합니다.A 와리즈턴을 반환합니다.A고유하고 그렇지 않으면 반복되는 위치에 오류 메시지가 있는 다른 배열을 반환합니다.
type AsUniqueArray<
A extends ReadonlyArray<any>,
B extends ReadonlyArray<any>
> = {
[I in keyof A]: unknown extends {
[J in keyof B]: J extends I ? never : B[J] extends A[I] ? unknown : never
}[number]
? Invalid<[A[I], "is repeated"]>
: A[I]
};
여기에서는 매핑된 유형과 조건부 유형을 많이 사용하지만 기본적으로 배열을 살펴보고 배열의 다른 요소가 현재 요소와 일치하는지 확인합니다.그렇다면 오류 메시지가 표시됩니다.
이제 도우미 기능입니다.또다른주기본다로같음기다니능입은과 같은 이 있다는 입니다.doSomething([1,2,3])치료할 것입니다[1,2,3]number[] 대로가 .[1,2,3]문학 작품 한 권이 문제를 해결하는 간단한 방법은 없으므로 이상한 마법을 사용해야 합니다(마법에 대한 자세한 내용은 링크 참조).
type Narrowable =
| string
| number
| boolean
| object
| null
| undefined
| symbol;
const asUniqueArray = <
N extends Narrowable,
A extends [] | ReadonlyArray<N> & AsUniqueArray<A, A>
>(
a: A
) => a;
지금이다,asUniqueArray()실행 시에만 입력을 반환하지만 컴파일 시에는 고유한 것으로 인식되는 배열 유형만 허용하며, 다음과 같은 반복이 있을 경우 문제 요소에 오류를 발생시킵니다.
const okay = asUniqueArray([1, 2, 3]); // okay
const notOkay = asUniqueArray([1, 2, 2]); // error!
// ~ ~
// number is not assignable to Invalid<[2, "is repeated"]> | undefined
만세, 그게 당신이 원했던 거죠, 그렇죠?처음부터 주의해야 할 사항은 그대로 유지되므로, 이미 확장된 어레이(비튜플 또는 비문자열)를 얻게 되면 다음과 같은 바람직하지 않은 동작을 하게 됩니다.
const generalArray: number[] = [1, 2, 2, 1, 2, 1, 2];
const doesntCareAboutGeneralArrays = asUniqueArray(generalArray); // no error
const arrayOfWideTypes: [number, number] = [1, 2];
const cannotSeeThatNumbersAreDifferent = asUniqueArray(arrayOfWideTypes); // error,
// Invalid<[number, "is repeated"]>
어쨌든, 이 모든 것들이 여러분에게 가치가 없을지도 모르지만, 저는 이것에 접근할 수 있는 일종의, 어쩌면, 활자 시스템이 있다는 것을 보여주고 싶었습니다.도움이 되길 바랍니다; 행운을 빕니다!
네! TypeScript 4.1(작성 당시 베타 버전)을 사용하는 방법이 있습니다.방법:
const data = ["11", "test", "tes", "1", "testing"] as const
const uniqueData: UniqueArray<typeof data> = data
type UniqueArray<T> =
T extends readonly [infer X, ...infer Rest]
? InArray<Rest, X> extends true
? ['Encountered value with duplicates:', X]
: readonly [X, ...UniqueArray<Rest>]
: T
type InArray<T, X> =
T extends readonly [X, ...infer _Rest]
? true
: T extends readonly [X]
? true
: T extends readonly [infer _, ...infer Rest]
? InArray<Rest, X>
: false
동일한 값이 두 번 이상 발생하면 컴파일러 오류가 발생합니다.
TypeScript Playground에서 사용해 보기
승인된 답변과 매우 유사하지만,InArray단순화되고 인라인화됩니다.
type IsUnique<A extends readonly unknown[]> =
A extends readonly [infer X, ...infer Rest]
? X extends Rest[number]
? [never, 'Encountered value with duplicates:', X] // false
: IsUnique<Rest>
: true;
type IsInArray<A extends readonly unknown[], X> = X extends A[number] ? true : false;
type TestA = IsUnique<["A","B","C"]>; // true
type TestB = IsUnique<["A","B","B"]>; // [never, "Encountered value with duplicates:", "B"]
하지만 또 다른 읽을 만한 해결책이 있습니다.
type ExcludeByIndex<T extends readonly unknown[], I extends keyof T & (number | string)> = {
[X in keyof T]: X extends (`${I}` | I) ? never : T[X]
}
export type ExcludeNotUnique<T extends readonly unknown[]> = {
[I in keyof T]-?: T[I] extends ExcludeByIndex<T, I>[number] ? never : T[I]
}
const ids = [1, 2, 2, 3, 4, 5] as const;
type UniqueIds = ExcludeNotUnique<typeof ids>;
function DummyUniqueIdsTest(): UniqueIds[number] {
return ids[Math.random()];
}
있는 으로 묶은 합니다.Array.from(mySet).
function someFn(map: List, keysSet: Set<keyof List>) {
const uniqueValue = Array.from(keysSet);
}
이렇게 하면 복제를 하더라도 문제가 되지 않습니다.
유형 스크립트는 컴파일 시간 검사만 수행합니다.런타임에 배열을 수정하는 것은 유형 스크립트에서 탐지할 수 없습니다.반면에 중복 항목이 삽입되지 않도록 설정 클래스를 사용할 수도 있습니다. 그러나 반환 값을 선택하지 않으면 오류가 발생하지 않습니다.그러나 컴파일 시간 오류는 발생하지 않습니다.
간단한 솔루션을 원하는 사용자를 위한 해결 방법:
개체를 생성하면 다음과 같은 오류가 발생합니다.
const anObject = {
1: 0,
2: 0,
2: 0, //will throw error
}
하지만 문제는 키가 문자열이기 때문에 문자열 이외에는 키에 저장할 수 없다는 것입니다.
const anObject = {
1: 0,
2: 0,
"2": 0, //will throw error
"foo": 0
}
숫자와 문자열이 모두 포함된 고유한 배열을 사용하지 않으려는 경우 이 방법이 효과적일 수 있습니다.그런 다음 다음과 같은 개체를 사용할 수 있습니다.
Object.keys(anObject)
배열로 사용합니다.
Typescript는 값이 아닌 유형만 참조하며 런타임 배열에서는 아무 작업도 수행하지 않습니다.
언급URL : https://stackoverflow.com/questions/57016728/is-there-a-way-to-define-type-for-array-with-unique-items-in-typescript
'programing' 카테고리의 다른 글
| Oracle의 기본 DATE 형식 (0) | 2023.07.04 |
|---|---|
| 단일 커밋을 여러 개발자에게 귀속시키는 방법은 무엇입니까? (0) | 2023.07.04 |
| Oracle varchar2에 정의 매개 변수로 필수 크기가 있는 이유는 무엇입니까? (0) | 2023.07.04 |
| LFol igit repo 및 작업 복사본 강제 적용 (0) | 2023.07.04 |
| WooCommerce 제품 검색을 사용하여 특정 post_type 양식 post_type 열을 검색하는 중 오류 발생 (0) | 2023.07.04 |