문자열 조합과 문자열 배열
다음과 같은 현악기 조합 타입이 있습니다.
type Suit = 'hearts' | 'diamonds' | 'spades' | 'clubs';
이 문자열 조합에서 사용할 수 있는 모든 가능한 값을 얻을 수 있는 안전한 방법을 원합니다.그러나 인터페이스는 대부분 디자인 타임컨스트럭트이기 때문에 제가 할 수 있는 최선의 방법은 다음과 같습니다.
export const ALL_SUITS = getAllStringUnionValues<Suit>({
hearts: 0,
diamonds: 0,
spades: 0,
clubs: 0
});
export function getAllStringUnionValues<TStringUnion extends string>(valuesAsKeys: { [K in TStringUnion]: 0 }): TStringUnion[] {
const result = Object.getOwnPropertyNames(valuesAsKeys);
return result as any;
}
이것은 정상적으로 동작합니다.함수는 각 키가 문자열 유니언의 요소이고 모든 요소가 포함된 개체를 항상 전달하고 모든 요소의 문자열 배열을 반환합니다.따라서 문자열 결합이 변경되면 이 함수에 대한 호출도 업데이트되지 않으면 컴파일 시 오류가 발생합니다.
단, 상수의 타입 시그니처에 문제가 있습니다.ALL_SUITS
('hearts' | 'diamonds' | 'spades' | 'clubs')[]
TypeScript는 을 한 번만 TypeScript)이 아니라 중복된 ['hearts', 'diamonds', 'spades', 'clubs']
.
가 정말 것은 이야.getAllStringUnionValues
를 반환하도록 ['hearts', 'diamonds', 'spades', 'clubs']
.
가능한 한 드라이하면서 일반적인 방법으로 이 작업을 수행할 수 있는 방법은 무엇입니까?
TypeScript 3.4 이상에 대한 답변
TypeScript에서는 유니언을 태플로 변환할 수 없습니다.적어도 정상적으로 동작하는 방식은 아닙니다.결합은 순서가 매겨지지 않도록 설계되어 있고 튜플은 본질적으로 순서가 매겨져 있기 때문에 사용자가 할 수 있더라도 결과 튜플은 예기치 않은 방식으로 동작할 수 있습니다.유니언으로부터 실제로 태플을 생성하지만 얼마나 취약한지에 대한 많은 주의사항이 있는 방법에 대해서는 이 답변을 참조하십시오.또, 이것이 서포트되고 있지 않은 이유에 대해서는, 「microsoft/TypeScript#13298」을 참조해 주세요.이태플로의 변환에 대한 거부된 기능 요구)를 참조해 주세요.
그러나 사용 사례에 따라서는 문제를 반전시킬 수 있습니다. 즉, 태플 유형을 명시적으로 지정하고 이 유형에서 결합을 도출할 수 있습니다.이것은 비교적 간단하다.
TypeScript 3.4부터는 다음과 같은 어설션을 사용하여 컴파일러에게 리터럴의 튜플 유형을 리터럴의 튜플로서 추론하도록 지시할 수 있습니다.string[]
은 모든 것을 다 것을 하여 어떤하는 경향이 있습니다.readonly
할 수
const ALL_SUITS = ['hearts', 'diamonds', 'spades', 'clubs'] as const;
type SuitTuple = typeof ALL_SUITS; // readonly ['hearts', 'diamonds', 'spades', 'clubs']
type Suit = SuitTuple[number]; // "hearts" | "diamonds" | "spades" | "clubs"
TypeScript 3.0~3.3에 대한 답변
TypeScript 3.0부터는 TypeScript가 자동으로 태플 타입을 추론할 수 있을 것으로 보입니다.그게 공개되면tuple()
필요한 함수는 다음과 같이 간결하게 기술할 수 있습니다.
export type Lit = string | number | boolean | undefined | null | void | {};
export const tuple = <T extends Lit[]>(...args: T) => args;
그리고 다음과 같이 사용할 수 있습니다.
const ALL_SUITS = tuple('hearts', 'diamonds', 'spades', 'clubs');
type SuitTuple = typeof ALL_SUITS;
type Suit = SuitTuple[number]; // union type
3.0 이전 버전의 TypeScript에 대한 답변
이 답변을 올렸기 때문에 라이브러리에 함수를 추가할 의향이 있다면 태플 타입을 추론할 수 있는 방법을 찾았습니다.도 이 해 보세요.tuple()
tuple.ts로 표시됩니다.
이것을 사용하면, 다음과 같이 쓸 수 있어 반복하지 않아도 됩니다.
const ALL_SUITS = tuple('hearts', 'diamonds', 'spades', 'clubs');
type SuitTuple = typeof ALL_SUITS;
type Suit = SuitTuple[number]; // union type
원답
원하는 것을 얻기 위한 가장 간단한 방법은 TypeScript가 어떻게 해야 하는지 모르는 역순으로 실행하도록 강요하지 않고 태플 유형을 명시적으로 지정하고 그것으로부터 결합을 도출하는 것입니다.예를 들어 다음과 같습니다.
type SuitTuple = ['hearts', 'diamonds', 'spades', 'clubs'];
const ALL_SUITS: SuitTuple = ['hearts', 'diamonds', 'spades', 'clubs']; // extra/missing would warn you
type Suit = SuitTuple[number]; // union type
을 두 번 , 한 .SuitTuple
, 1회, , 1회, 1회.ALL_SUITS
TypeScript는 현재 튜플을 추론하도록 지시할 수 없으며, 태플 유형에서 런타임 배열을 생성하지 않기 때문에 이러한 반복을 피할 수 있는 좋은 방법은 없습니다.
이 방법의 장점은 실행 시 더미 개체의 키 열거가 필요하지 않다는 것입니다.물론 여전히 필요한 경우 수트를 키로 활자를 만들 수 있습니다.
const symbols: {[K in Suit]: string} = {
hearts: '♥',
diamonds: '♦',
spades: '♠',
clubs: '♣'
}
TypeScript 3.4 업데이트:
TypeScript 3.4에는 "const contexts"라고 불리는 보다 간결한 구문이 제공됩니다.이미 마스터에 병합되어 이 PR에서 볼 수 있듯이 곧 사용할 수 있게 될 것입니다.
「)」할 수 .as const
★★★★★★★★★★★★★★★★★」<const>
키워드를 지정합니다.수 타입을 하게 상정할 수 .['a', 'b']
넓이 대신('a' | 'b')[]
또는 심지어string[]
하면, 「이러다」, 「이러다」의할 수 .tuple()
★★★★★★ 。
질문을 참조하기 위해
단, 문제는 ALL_SUITS가 항상 ('하트' | '다이아몬드' | '스페이드' | '클럽')[. (...그래야 합니다) ['하트', '다이아몬드', '스페이드', '클럽']이라는 형식 서명입니다.
새로운 구문을 사용하면 다음 사항을 정확하게 달성할 수 있습니다.
const ALL_SUITS = <const> ['hearts', 'diamonds', 'spades', 'clubs'];
// or
const ALL_SUITS = ['hearts', 'diamonds', 'spades', 'clubs'] as const;
// type of ALL_SUITS is infererd to ['hearts', 'diamonds', 'spades', 'clubs']
이 불변 어레이를 사용하면 원하는 유니언 유형을 쉽게 만들 수 있습니다.
type Suits = typeof ALL_SUITS[number]
마음가짐이 편안하고 옳다.
문자열 조합과 문자열 배열 - 올바른 결정!
type ValueOf<T> = T[keyof T];
type NonEmptyArray<T> = [T, ...T[]]
type MustInclude<T, U extends T[]> = [T] extends [ValueOf<U>] ? U : never;
function stringUnionToArray<T>() {
return <U extends NonEmptyArray<T>>(...elements: MustInclude<T, U>) => elements;
}
/* USAGE */
type Variants = "error" | "success" | "info";
// This is what You want!! :)
let stringArray = stringUnionToArray<Variants>()("error", "success", "info");
@jcalz가 말했듯이 유니언 타입의 튜플 타입은 만들 수 없습니다.태플은 명령되어 있기 때문에 유니언 타입이 아닙니다.그러나 입력 결합의 모든 값을 포함하는 가능한 모든 태플 유형의 새 결합을 작성할 수 있습니다.
예:
type U2O<U extends string> = {
[key in U]: U2O<Exclude<U, key>>;
}
type O2T<O extends {}> = {} extends O ? [] : {
[key in keyof O]: [key, ...O2T<O[key]>];
}[keyof O]
type InputUnion = 'a' | 'b' | 'c'
type UnionOfPossibleTuples = O2T<U2O<InputUnion>>
// Now `UnionOfPossibleTuples` equals to ["a", "b", "c"] | ["a", "c", "b"] | ["b", "a", "c"] | ["b", "c", "a"] | ["c", "a", "b"] | ["c", "b", "a"]
문자열 결합을 중복되지 않는 배열로 변환하는 방법
사용.keyof
우리는 결합을 객체의 키 배열로 바꿀 수 있다.그것은 어레이에 다시 적용할 수 있습니다.
type Diff<T, U> = T extends U ? never : T;
interface IEdiatblePartOfObject {
name: string;
}
/**
* At least one key must be present,
* otherwise anything would be assignable to `keys` object.
*/
interface IFullObject extends IEdiatblePartOfObject {
potato: string;
}
type toRemove = Diff<keyof IFullObject, keyof IEdiatblePartOfObject>;
const keys: { [keys in toRemove]: any } = {
potato: void 0,
};
const toRemove: toRemove[] = Object.keys(keys) as any;
이 메서드는 오버헤드를 생성하지만 누군가가 새 키를 추가하면 오류가 발생합니다.IFullObject
.
보너스:
declare const safeData: IFullObject;
const originalValues: { [keys in toRemove]: IFullObject[toRemove] } = {
potato: safeData.potato || '',
};
/**
* This will contain user provided object,
* while keeping original keys that are not alowed to be modified
*/
Object.assign(unsafeObject, originalValues);
지정된 배열이 기존 유니언 유형의 모든 요소와 일치하는지 확인하는 경우 허용되는 답변으로는 충분하지 않을 수 있습니다.
다음은 함수 호출을 사용하여 컴파일 시 제공된 배열이 지정된 조합과 일치하는지 확인하는 솔루션입니다.
type NoneEmptyArray = readonly any[] & {0: any}
type CompareUnionWithArray<P, Q extends NoneEmptyArray> = Exclude<P, Q[number]> extends never
? (Exclude<Q[number], P> extends never ? Q : ReadonlyArray<P>)
: readonly [...Q, Exclude<P, Q[number]>]
export function assertTypeEquals<P, Q extends NoneEmptyArray>(test: CompareUnionWithArray<P, Q>): void {}
Test Example:
type Suit = 'hearts' | 'diamonds' | 'spades' | 'clubs'
const matchingArray = ['hearts', 'diamonds', 'spades', 'clubs'] as const
const emptyArray = [] as const
const unknownElements = ['hearts', 'diamonds', 'spades', 'clubs', 'UNKNOWN'] as const
const missingElements = ['hearts', 'diamonds', "clubs"] as const
assertTypeEquals<Suit, (typeof matchingArray)>(matchingArray) // no error
assertTypeEquals<Suit, (typeof emptyArray)>(missingElements) // fails because empty array is not allowed
assertTypeEquals<Suit, (typeof unknownElements)>(unknownElements) // fails with: Type '"UNKNOWN"' is not assignable to type 'Suit'.
assertTypeEquals<Suit, (typeof missingElements)>(missingElements) // fails with:
// Argument of type 'readonly ["hearts", "diamonds", "clubs"]' is not assignable to
// parameter of type 'readonly ["hearts", "diamonds", "clubs", "spades"]'.
// Source has 3 element(s) but target requires 4.
업데이트: 불필요한 상수가 필요하지 않고 보다 유용한 오류 메시지가 생성되도록 코드가 개선되었습니다.
언급URL : https://stackoverflow.com/questions/44480644/string-union-to-string-array
'programing' 카테고리의 다른 글
SwiftyJ를 사용하여 문자열을 JSON으로 변환하는 방법아들. (0) | 2023.03.08 |
---|---|
MongoDB - 페이징 (0) | 2023.03.08 |
이것은 WordPress의 .htaccess 코드입니다.누가 설명 좀 해줄래? (0) | 2023.03.08 |
Simple Wordpress AJAX 페이지 번호부여부 (0) | 2023.03.08 |
Spring Crud Repository .orelse던지다() (0) | 2023.03.08 |