나는 가질 수있는 인터페이스를 만들려고합니다
export interface MenuItem {
title: string;
component?: any;
click?: any;
icon: string;
}
- 요구
component
하거나click
설정할 방법이 있습니까? - 두 속성을 모두 설정할 수 없도록 요구하는 방법이 있습니까?
답변
유형이 조건부 논리가없고 서로 의존 할 수 없기 때문에 단일 인터페이스가 아니라 인터페이스를 분할하여 사용할 수 있습니다.
export interface BaseMenuItem {
title: string;
icon: string;
}
export interface ComponentMenuItem extends BaseMenuItem {
component: any;
}
export interface ClickMenuItem extends BaseMenuItem {
click: any;
}
export type MenuItem = ComponentMenuItem | ClickMenuItem;
답변
Exclude
TypeScript 2.8에 추가 된 유형 의 도움으로 속성 집합 중 하나 이상을 요구하는 일반화 가능한 방법은 다음과 같습니다.
type RequireAtLeastOne<T, Keys extends keyof T = keyof T> =
Pick<T, Exclude<keyof T, Keys>>
& {
[K in Keys]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<Keys, K>>>
}[Keys]
그리고 단 하나만 제공되도록 요구하는 부분적이지만 절대적인 방법은 다음과 같습니다.
type RequireOnlyOne<T, Keys extends keyof T = keyof T> =
Pick<T, Exclude<keyof T, Keys>>
& {
[K in Keys]-?:
Required<Pick<T, K>>
& Partial<Record<Exclude<Keys, K>, undefined>>
}[Keys]
다음은 작동중인 두 가지를 모두 보여주는 TypeScript 플레이 그라운드 링크입니다.
주의 할 점 RequireOnlyOne
은 TypeScript가 런타임에 존재하는 모든 속성을 컴파일 할 때 항상 알 수는 없다는 것입니다. 그래서 분명히 RequireOnlyOne
알지 못하는 추가 속성을 방지하기 위해 아무것도 할 수 없습니다. RequireOnlyOne
놀이터 링크 끝에서 놓칠 수 있는 방법의 예를 제공했습니다 .
다음 예제를 사용하여 작동 방식에 대한 간략한 개요 :
interface MenuItem {
title: string;
component?: number;
click?: number;
icon: string;
}
type ClickOrComponent = RequireAtLeastOne<MenuItem, 'click' | 'component'>
-
Pick<T, Exclude<keyof T, Keys>>
fromRequireAtLeastOne
은{ title: string, icon: string}
에 포함되지 않은 키의 변경되지 않은 속성입니다.'click' | 'component'
-
{ [K in Keys]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<Keys, K>>> }[Keys]
에서RequireAtLeastOne
이된다{ component: Required<{ component?: number }> & { click?: number }, click: Required<{ click?: number }> & { component?: number } }[Keys]
어느 것이
{ component: { component: number, click?: number }, click: { click: number, component?: number } }['component' | 'click']
마침내
{component: number, click?: number} | {click: number, component?: number}
-
위의 1 단계와 2 단계의 교차점
{ title: string, icon: string} & ({component: number, click?: number} | {click: number, component?: number})
단순화
{ title: string, icon: string, component: number, click?: number} | { title: string, icon: string, click: number, component?: number}
답변
복잡한 조건부 유형 을 사용할 필요가 없습니다 . 더 간단하게 만들 수 있습니다.
- 구성 요소를 요구하거나 클릭하여 설정하는 방법이 있습니까? (포함
OR
)
type MenuItemOr = {
title: string;
icon: string;
} & ({ component: object } | { click: boolean })
// brackets are important here: "&" has precedence over "|"
let testOr: MenuItemOr;
testOr = { title: "t", icon: "i" } // error, none are set
testOr = { title: "t", icon: "i", component: {} } // ✔
testOr = { title: "t", icon: "i", click: true } // ✔
testOr = { title: "t", icon: "i", click: true, component: {} } // ✔
조합 유형은 ( |
) 포괄적으로 대응 OR
. 그것은되는 교차 비 조건부 속성.
- 두 속성을 모두 설정할 수 없도록 요구하는 방법이 있습니까? (독점
OR
/XOR
)
type MenuItemXor = {
title: string;
icon: string;
} & (
| { component: object; click?: never }
| { component?: never; click: boolean }
)
let testXor: MenuItemXor;
testXor = { title: "t", icon: "i" } // error, none are set
testXor = { title: "t", icon: "i", component: {} } // ✔
testXor = { title: "t", icon: "i", click: true } // ✔
testXor = { title: "t", icon: "i", click: true, component: {} } // error, both are set
기본적으로 둘 중 하나 component
또는 click
설정할 수 있으며 다른 하나는 동시에 추가 해서는 안됩니다 . TS는 할 수 있습니다 차별 노동 조합 유형을 밖으로 MenuItemXor
에있는 해당한다, XOR
.
참고 :이 XOR
조건 MenuItemXor
은 수락 된 답변으로 는 불가능합니다 .
답변
여러 인터페이스가없는 대안은 다음과 같습니다.
export type MenuItem = {
title: string;
component: any;
icon: string;
} | {
title: string;
click: any;
icon: string;
};
const item: MenuItem[] = [
{ title: "", icon: "", component: {} },
{ title: "", icon: "", click: "" },
// Shouldn't this error out because it's passing a property that is not defined
{ title: "", icon: "", click: "", component: {} },
// Does error out :)
{ title: "", icon: "" }
];
단일 속성을 설정해야하는 Partial-like를 만드는 방법 에서 비슷한 질문을했습니다.
위 내용은 단순화 될 수 있지만 읽기가 더 쉬울 수도 있고 그렇지 않을 수도 있습니다.
export type MenuItem = {
title: string;
icon: string;
} & (
{component: any} | {click: string}
)
TypeScript는 AND / OR를 사용하는 개체에 대한 추가 속성을 허용하기 때문에 이들 중 어느 것도 둘 다 추가 할 수 없습니다. https://github.com/Microsoft/TypeScript/issues/15447 참조
답변
나는 결국 :
export interface MenuItem {
title: string;
icon: string;
}
export interface MenuItemComponent extends MenuItem{
component: any;
}
export interface MenuItemClick extends MenuItem{
click: any;
}
그런 다음 사용했습니다.
appMenuItems: Array<MenuItemComponent|MenuItemClick>;
그러나 단일 인터페이스로 모델링하는 방법이 있기를 바랐습니다.
답변
Pick
이러한 종류의 조건부 요구 사항을 설정하기 위해 모든 속성을 포함하는 기본 유형과 함께 사용하는 것을 좋아 합니다.
interface MenuItemProps {
title: string;
component: any;
click: any;
icon: string;
}
export interface MenuItem =
Pick<MenuItemProps, "title" | "icon" | "component"> |
Pick<MenuItemProps, "title" | "icon" | "click">
이것은 깨끗하고 유연합니다. 선언을 간단하고 읽기 쉽게 유지하면서 “모든 속성,이 두 속성 만 필요 또는이 속성 하나만 필요”등과 같은 것을 주장하면서 요구 사항에 대해 임의로 복잡해질 수 있습니다.
답변
나는 이것을 사용한다 :
type RequireField<T, K extends keyof T> = T & Required<Pick<T, K>>
용법:
let a : RequireField<TypeA, "fieldA" | "fieldB">;
이 수 fieldA
및 fieldB
필요 .
