typescript 인터페이스에는 두 가지 속성 중 하나가 필요합니다.
이 인터페이스를 만들고 있습니다.
export interface MenuItem {
title: string;
component?: any;
click?: any;
icon: string;
}
component
★★★★★★★★★★★★★★★★★」click
- 두 속성을 모두 설정할 수 없도록 요구하는 방법이 있습니까?
「 」의 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 playground 링크입니다.이 링크에서는 양쪽이 동작하고 있습니다.
「 」의 .RequireOnlyOne
TypeScript가 컴파일 시 런타임에 존재하는 모든 속성을 항상 알 수 있는 것은 아닙니다. So obviously 그러니 당연하게도RequireOnlyOne
추가 속성을 방지하기 위해 아무것도 할 수 없습니다.알지 못하는 추가 속성을 막기 위해 아무것도 할 수 없습니다. I provided an example of how 제가 예를 들어 설명 드렸는데요.RequireOnlyOne
놀이터 링크의 끝에 놓으면 할 수 있다.놀이터 링크 끝에 있는 것을 놓칠 수 있습니다.
다음 예를 사용하여 동작의 개요를 나타냅니다.
interface MenuItem {
title: string;
component?: number;
click?: number;
icon: string;
}
type ClickOrComponent = RequireAtLeastOne<MenuItem, 'click' | 'component'>
Pick<T, Exclude<keyof T, Keys>>
부에서RequireAtLeastOne
다가 되다{ title: string, icon: string}
, 함 포 되 지 은 경 의 성 은 되 which속 not않다니입 in변 proper지 included키ties에않 of are the keys the unchanged which not ..'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}
단일 인터페이스에서는 사용할 수 없습니다.타입에는 조건부 로직이 없고 서로 의존할 수 없기 때문에 인터페이스를 분할하여 다음과 같이 할 수 있습니다.
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;
더 간단한 해결책이 있습니다.다음과 같은 복잡한 조건 유형을 사용할 필요가 없습니다.
- 컴포넌트 또는 클릭을 설정하도록 요구하는 방법이 있습니까? (포함)
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: {} } // ✔
유니언 타입(|
) corresponds to inclusive )는 포함에 대응합니다.OR
. 이것은 무조건적인 속성과 교차합니다.
연산자를 사용하여 값을 다음 구성 요소 중 하나로 다시 좁힙니다.
if ("click" in testOr) testOr.click // works
- 두 속성을 모두 설정할 수 없도록 요구하는 방법이 있습니까? (Exclusive / )
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 set
기본적으로 어느 쪽인가 하면 component
or or or openicle. click
설정할 수 있습니다.다른 하나를 동시에 추가해서는 안 됩니다.TS는 다음과 같은 식별된 유니언 유형을 만들 수 있습니다.MenuItemXor
경우, 이 경우, 이 말은 에 해당됩니다.XOR
.
★★★★★★★★★★★★★★★★★.XOR
입니다.MenuItemXor
수락된 답변으로는 불가능합니다.
1 말하면, 「 」입니다.prop?: never
prop?: undefined
하지만 전자는 종종 일러스트레이션에 사용됩니다.
인터페이스가 여러 개 없는 대체 방법은
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: "" }
];
단일 속성을 설정해야 하는 부분 유사 생성 방법에서 유사한 질문을 했습니다.
위의 내용은 단순화할 수 있지만 읽기 쉬울 수도 있고 그렇지 않을 수도 있습니다.
export type MenuItem = {
title: string;
icon: string;
} & (
{component: any} | {click: string}
)
TypeScript 에서는 AND/OR 를 사용하는 오브젝트에 대한 추가 속성을 사용할 수 있기 때문에 둘 다 추가할 수 없습니다.https://github.com/Microsoft/TypeScript/issues/15447 를 참조해 주세요.
나는 이것을 사용한다.
type RequireField<T, K extends keyof T> = T & Required<Pick<T, K>>
사용방법:
let a : RequireField<TypeA, "fieldA" | "fieldB">;
이렇게 하면fieldA
그리고. fieldB
필수의.
나는 결국 다음과 같이 되었다.
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 MenuItem = {
title: string;
component: any;
click?: never;
icon: string;
} | {
title: string;
component?: never;
click: any;
icon: string;
}
// good
const menuItemWithComponent: MenuItem = {
title: 'title',
component: "my component",
icon: "icon"
}
// good
const menuItemWithClick: MenuItem = {
title: 'title',
click: "my click",
icon: "icon"
}
// compile error
const menuItemWithBoth: MenuItem = {
title: 'title',
click: "my click",
component: "my click",
icon: "icon"
}
또 다른 솔루션:
type RequiredKeys<T, K extends keyof T> = Required<Pick<T, K>> & Omit<T, K>;
type MenuItem2 = RequiredKeys<MenuItem, "component" | "click">;
이 어프로치에서는,never
그리고.Omit
. 여기서 얻을 수 있는 이점은 알기 쉽고 속성을 추가해야 할 경우에도 쉽게 업데이트할 수 있다는 것입니다.
interface Base {
title: string;
icon: string;
component?: never;
click?: never;
}
interface OnlyComponent {
component: any;
}
interface OnlyClick {
click: any;
}
export type MenuItem = (Omit<Base, 'component'> & OnlyComponent) | (Omit<Base, 'click'> & OnlyClick);
사용할 수 있습니다.in
사례를 좁히다MenuItem
:
const item: MenuItem = {
title: 'A good title';
icon: 'fa-plus';
component: SomeComponent;
};
//...
if('component' in item) {
const Comp = item.component;
//...
}
위의 멋진 답변만 더하면 됩니다!또한 필요한 기능을 갖춘 Partial 버전을 찾는 동안 이곳에 도착한 사람들을 위해!여기 내가 찍으려고 만든 조각이 있어!
부분 요구
인터페이스의 일부를 사용하는 경우, 그 사이에 일부 필드가 필요합니다.어떻게 하면 좋을까
export type PartialReq<T, Keys extends keyof T = keyof T> =
Pick<Partial<T>, Exclude<keyof T, Keys>>
& {
[K in Keys]: T[K]
};
예제를 사용하다
export interface CacheObj<SigType = any, ValType = any> {
cache: Map<SigType, ValType>,
insertionCallback: InsertionCallback<SigType, ValType> // I want this to be required
}
// ...
export class OneFlexibleCache<SigType = any, ValType = any> {
private _cacheObj: CacheObj<SigType, ValType>;
constructor(
cacheObj: PartialReq<CacheObj<SigType, ValType>, 'insertionCallback'> // <-- here
// i used it
) {
cacheObj = cacheObj || {};
this._cacheObj = {
// ...
// _______________ usage
this._caches.set(
cacheSignature,
new OneFlexibleCache<InsertionSigType, InsertionValType>({
insertionCallback // required need to be provided
})
);
여기 보면 완벽하게 동작하는 것을 알 수 있습니다.
필요한 정보가 제공되지 않은 경우
업데이트: 위에서 설명한 사용법에 대해 더 나은 답변을 제시합니다.
의사한테 가보니 오미트가 있더군요
https://www.typescriptlang.org/docs/handbook/utility-types.html#omittk
추가하러 왔어요.그런데 그 전에 이 멋진 대답을 봤어요.모두 대상:
https://stackoverflow.com/a/48216010/7668448
이것 좀 봐!모든 다양한 버전의 Typescript에 대해 이 작업을 수행하는 방법을 보여 줍니다.그리고 반복하지 않기 위해서! 가서 확인해봐!
언급URL : https://stackoverflow.com/questions/40510611/typescript-interface-require-one-of-two-properties-to-exist
'programing' 카테고리의 다른 글
AngularJS 디렉티브 제한 A와 E (0) | 2023.04.04 |
---|---|
wordpress에서 wp_mail() 함수를 사용하는 방법 (0) | 2023.04.04 |
토큰 기반 인증을 사용하는 경우 이미지를 로드하는 방법 (0) | 2023.04.04 |
새로 고칠 때 (AJAX) URL 필터 매개 변수와 함께 AJAX 페이지화 작업 (0) | 2023.04.04 |
Angular ng-container에 대한 AngularJS 등가물 (0) | 2023.04.04 |