Typescript d.ts 파일에 정의된 인터페이스 속성 유형을 재정의하는 중
in type 스크립트에 정의된 인터페이스 속성 유형을 변경할 수 있는 방법이 있습니까?
예: 의 인터페이스는 다음과 같이 정의됩니다.
interface A {
property: number;
}
내가 쓰는 스크립트 파일 형식에서 변경하고 싶다.
interface A {
property: Object;
}
아니면 이마저도 효과가 있을 것이다.
interface B extends A {
property: Object;
}
이 접근법이 효과가 있을까요? 내가 시스템을 사용해봤을 때 작동하지 않았다. 그게 가능한지 확인하고 싶어서요?
기존 속성의 유형을 변경할 수 없습니다.
속성을 추가할 수 있습니다.
interface A {
newProperty: any;
}
그러나 기존 유형의 변경:
interface A {
property: any;
}
오류가 발생합니다.
후속 변수 선언의 형식은 동일해야 합니다. 변수 'property'는 'number' 유형이어야 하지만 여기에는 'any' 유형이 있습니다.
물론 기존 인터페이스를 확장하는 자신만의 인터페이스를 가질 수 있다. 이 경우 다음과 같이 유형을 호환되는 유형으로만 재정의할 수 있습니다.
interface A {
x: string | number;
}
interface B extends A {
x: number;
}
그나저나, 당신은 아마도 타입으로 사용하는 것을 피하고, 타입을 사용해야 할 것이다.
다음과 같이 명시되어 있습니다.
모든 유형은 기존 JavaScript에서 작업할 수 있는 강력한 방법으로 컴파일 중에 형식 검사를 점차적으로 선택 및 해제할 수 있습니다.아웃할 수 있습니다. 오브젝트가 다른 언어에서와 유사한 역할을 수행할 것으로 예상할 수 있습니다. :
let notSure: any = 4;
notSure.ifItExists(); // okay, ifItExists might exist at runtime
notSure.toFixed(); // okay, toFixed exists (but the compiler doesn't check)
let prettySure: Object = 4;
prettySure.toFixed(); // Error: Property 'toFixed' doesn't exist on type 'Object'.
같은 사건을 해결할 가능성을 조사하느라 하루를 보내는 게 웃기네요. 나는 이렇게 하는 것이 불가능하다는 것을 알았다.
// a.ts - module
export interface A {
x: string | any;
}
// b.ts - module
import {A} from './a';
type SomeOtherType = {
coolStuff: number
}
interface B extends A {
x: SomeOtherType;
}
원인 A 모듈은 당신의 응용 프로그램에서 사용 가능한 모든 유형을 알지 못할 수 있다. 그리고 모든 곳에서 이런 코드를 하는 것은 꽤 지루한 항구입니다.
export interface A {
x: A | B | C | D ... Million Types Later
}
나중에 유형을 정의해야 자동 완성이 잘 됩니다.
그래서 너는 조금 속일 수 있다:
// a.ts - module
export interface A {
x: string;
}
재정의할 필요가 없는 경우 자동 완성 작업을 허용하는 일부 유형을 기본적으로 남겨두었습니다.
그리고나서
// b.ts - module
import {A} from './a';
type SomeOtherType = {
coolStuff: number
}
// @ts-ignore
interface B extends A {
x: SomeOtherType;
}
깃발을 사용하여 우리가 잘못하고 있다고 말하는 어리석은 예외를 여기서 비활성화하십시오. 그리고 웃긴 것은 모든 것이 예상대로 작동한다는 것이다.
내 경우, 나는 유형의 범위 시야를 줄이고, 그것은 내가 코드를 더 엄격하게 할 수 있게 해준다. 예를 들어, 당신은 100개의 부동산 목록을 가지고 있고 바보 같은 상황을 피하기 위해 그것을 10개로 줄인다.
필드를 먼저 필터링한 다음 결합하는 방법을 사용합니다.
언급
interface A {
x: string
}
export type B = Omit<A, 'x'> & { x: number };
인터페이스의 경우:
interface A {
x: string
}
interface B extends Omit<A, 'x'> {
x: number
}
@zSkycat의 응답을 조금 확장하면 두 개체 유형을 수락하고 두 번째 개체 유형이 첫 번째 멤버를 재정의하는 병합 유형을 반환하는 제네릭을 만들 수 있습니다.
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
type Merge<M, N> = Omit<M, Extract<keyof M, keyof N>> & N;
interface A {
name: string;
color?: string;
}
// redefine name to be string | number
type B = Merge<A, {
name: string | number;
favorite?: boolean;
}>;
let one: A = {
name: 'asdf',
color: 'blue'
};
// A can become B because the types are all compatible
let two: B = one;
let three: B = {
name: 1
};
three.name = 'Bee';
three.favorite = true;
three.color = 'green';
// B cannot become A because the type of name (string | number) isn't compatible
// with A even though the value is a string
// Error: Type {...} is not assignable to type A
let four: A = three;
type ModifiedType = Modify<OriginalType, {
a: number;
b: number;
}>
interface ModifiedInterface extends Modify<OriginalType, {
a: number;
b: number;
}> {}
솔루션에서 영감을 받아 다음과 같이 생각해냈습니다.
type Modify<T, R> = Omit<T, keyof R> & R; // before typescript@3.5 type Modify<T, R> = Pick<T, Exclude<keyof T, keyof R>> & R
예:
interface OriginalInterface {
a: string;
b: boolean;
c: number;
}
type ModifiedType = Modify<OriginalInterface , {
a: number;
b: number;
}>
// ModifiedType = { a: number; b: number; c: number; }
단계별 진행:
type R0 = Omit<OriginalType, 'a' | 'b'> // { c: number; }
type R1 = R0 & {a: number, b: number } // { a: number; b: number; c: number; }
type T0 = Exclude<'a' | 'b' | 'c' , 'a' | 'b'> // 'c'
type T1 = Pick<OriginalType, T0> // { c: number; }
type T2 = T1 & {a: number, b: number } // { a: number; b: number; c: number; }
심층 수정 v3
interface Original {
a: {
a: string
b: { a: string }
c: string
d: string // <- keep this one
}
}
interface Overrides {
a: {
a: { a: number } // <- overwrite string with object
b: number // <- overwrite object with number
c: number // <- overwrite string with number
e: number // <- new property
}
}
type ModifiedType = ModifyDeep<Original, Overrides>
interface ModifiedInterface extends ModifyDeep<Original, Overrides> {}
const example: ModifiedType = {
a: {
a: { a: number },
b: number,
c: number,
d: string,
e: number,
}
}
찾아내다.
이를 위해 다른 사용자가 일반 유틸리티 유형이 필요한 경우 다음과 같은 솔루션을 생각해냈습니다.
/**
* Returns object T, but with T[K] overridden to type U.
* @example
* type MyObject = { a: number, b: string }
* OverrideProperty<MyObject, "a", string> // returns { a: string, b: string }
*/
export type OverrideProperty<T, K extends keyof T, U> = Omit<T, K> & { [P in keyof Pick<T, K>]: U };
저는 이것이 필요했습니다. 왜냐하면 제 경우, 재정의하는 열쇠는 제네릭 그 자체였기 때문입니다.
준비가 안 된 경우, 을 참조하십시오.
속성 유형을 좁히기 위해 다음과 같이 간단한 작업이 완벽합니다.
interface A {
x: string | number;
}
interface B extends A {
x: number;
}
확폭 또는 일반적인 유형의 경우 다음을 수행할 수 있습니다.
interface A {
x: string
}
export type B = Omit<A, 'x'> & { x: number };
그러나 인터페이스가 일반 인터페이스를 확장하는 경우 을(를) 사용할 때 나머지 속성의 사용자 지정 유형이 손실됩니다.
예.
interface A extends Record<string | number, number | string | boolean> {
x: string;
y: boolean;
}
export type B = Omit<A, 'x'> & { x: number };
let b: B = { x: 2, y: "hi" }; // no error on b.y!
그 이유는, 내부적으로는 우리의 경우에 일반적일 키들만을 검토하기 때문입니다. 따라서 에서는 의 유형을 가진 모든 추가 속성을 허용하고 사용할 수 있습니다.
이를 해결하기 위해 다음과 같은 다른 유틸리티 유형을 고안했습니다.
type OverrideProps<M, N> = { [P in keyof M]: P extends keyof N ? N[P] : M[P] };
예:
type OverrideProps<M, N> = { [P in keyof M]: P extends keyof N ? N[P] : M[P] };
interface A extends Record<string | number, number | string | boolean> {
x: string;
y: boolean;
}
export type B = OverrideProps<A, { x: number }>;
let b: B = { x: 2, y: "hi" }; // error: b.y should be boolean!
인터페이스 확장 시 속성:
interface A {
a: number;
b: number;
}
interface B extends Omit<A, 'a'> {
a: boolean;
}
이전 답변이 작성되었을 때 이 답변에서 사용하는 구문을 사용할 수 있었는지 확실하지 않지만
이 항목(인터페이스 속성 덮어쓰기)과 관련된 몇 가지 문제가 있으며, 이 문제를 처리하는 방법은 다음과 같습니다.
- 먼저 사용할 수 있는 유형을 사용하여 일반 인터페이스를 만듭니다.
에서 볼 수 있듯이 일반 매개 변수에 대한 값 선택을 사용할 수도 있습니다.
type SOME_OBJECT = { foo: "bar" }
interface INTERFACE_A <T extends number | SOME_OBJECT = number> {
property: T;
}
- 그런 다음 일반 매개 변수에 값을 전달하여(또는 생략하고 기본값을 사용하여) 해당 계약에 따라 새 유형을 생성할 수 있습니다.
type A_NUMBER = INTERFACE_A; // USES THE default = number TYPE. SAME AS INTERFACE_A<number>
type A_SOME_OBJECT = INTERFACE_A<SOME_OBJECT> // MAKES { property: SOME_OBJECT }
그리고 그 결과는 다음과 같습니다.
const aNumber: A_NUMBER = {
property: 111 // THIS EXPECTS A NUMBER
}
const anObject: A_SOME_OBJECT = {
property: { // THIS EXPECTS SOME_OBJECT
foo: "bar"
}
}
나처럼 게으른 사람들을 위한 짧은 대답:
type Overrided = Omit<YourInterface, 'overrideField'> & { overrideField: <type> };
interface Overrided extends Omit<YourInterface, 'overrideField'> {
overrideField: <type>
}
날짜: 2021년 3월 19일 나는 최신 타입스크립트(4.1.2) 버전이 파일의 오버라이드를 지원하고 있다고 생각한다.
// in test.d.ts
interface A {
a: string
}
export interface B extends A {
a: number
}
// in any ts file
import { B } from 'test.d.ts'
// this will work
const test: B = { a: 3 }
// this will not work
const test1: B = { a: "3" }
기존 속성의 유형만 수정하고 제거하지 않으려는 경우 다음과 같이 하면 됩니다.
// Style that accepts both number and percent(string)
type BoxStyle = {
height?: string | number,
width?: string | number,
padding?: string | number,
borderRadius?: string | number,
}
// These are both valid
const box1: BoxStyle = {height: '20%', width: '20%', padding: 0, borderRadius: 5}
const box2: BoxStyle = {height: 85, width: 85, padding: 0, borderRadius: 5}
// Override height and width to be only numbers
type BoxStyleNumeric = BoxStyle & {
height?: number,
width?: number,
}
// This is still valid
const box3: BoxStyleNumeric = {height: 85, width: 85, padding: 0, borderRadius: 5}
// This is not valid anymore
const box4: BoxStyleNumeric = {height: '20%', width: '20%', padding: 0, borderRadius: 5}
유틸리티 유형 솔루션을 확장하여 의 키를 에 있는 키로 제한하고 IntelliSense를 추가합니다.
export type Modify<T, R extends Partial<Record<keyof T, any>>> = Omit<T, keyof R> & R;
를 기반으로 사용하기 편리하고 코드의 의도를 명확하게 설명하는 추상화된 제네릭 유형을 생성할 수 있습니다.
type Override<T, K extends keyof T, N> = Omit<T, K> & { [K1 in K]: N };
여기서:
- = 현존형
- = 재정의할 유형의 키
- = 재정의할 기존 유형의 키에 대한 새 유형
사용 예:
type GraphQLCodegenConfig = Override<CodegenConfig, 'schema', DocumentNode>;
수정자 유형 만들기
type Modify<T, R extends {[P in keyof T]:any} > = Omit<T, keyof R> & R;
그리고 할 수 있다.
interface ModifiedInterface extends Modify<OriginalType, {
a: number;
b: number;
}> {}
자동 완성 유형을 제공합니다.
다음 유형의 별칭을 사용할 수 있습니다.
type Override<T, K extends { [P in keyof T]: any } | string> =
K extends string
? Omit<T, K>
: Omit<T, keyof K> & K;
및 아래 구문에서 동일하게 사용합니다.
글로벌 인터페이스
interface IFirst {
username: string;
}
올바른 이름으로 인터페이스
interface ISecond extends Override<IFirst, 'username'> {
username: number;
}
별칭을 입력합니다.
type IThird = Override<IFirst, { username: boolean }>;
심층 수정 v3
*
interface Original {
a: {
a: string
b: { a: string }
c: string
d: string // <- keep this one
}
}
interface Overrides {
a: {
a: { a: number } // <- overwrite string with object
b: number // <- overwrite object with number
c: number // <- overwrite string with number
e: number // <- new property
}
}
type ModifiedType = ModifyDeep<Original, Overrides>
interface ModifiedInterface extends ModifyDeep<Original, Overrides> {}
const example: ModifiedType = {
a: {
a: { a: number },
b: number,
c: number,
d: string,
e: number,
}
}
type ModifyDeep<A, B extends DeepPartialAny<A>> = {
[K in keyof A | keyof B]: // For all keys in A and B:
K extends keyof A // ───┐
? K extends keyof B // ───┼─ key K exists in both A and B
? A[K] extends AnyObject // │ ┴──┐
? B[K] extends AnyObject // │ ───┼─ both A and B are objects
? ModifyDeep<A[K], B[K]> // │ │ └─── We need to go deeper (recursively)
: B[K] // │ ├─ B is a primitive 🠆 use B as the final type (new type)
: B[K] // │ └─ A is a primitive 🠆 use B as the final type (new type)
: A[K] // ├─ key only exists in A 🠆 use A as the final type (original type)
: B[K] // └─ key only exists in B 🠆 use B as the final type (new type)
}
type AnyObject = Record<string, any>
// This type is here only for some intellisense for the overrides object
type DeepPartialAny<T> = {
/** Makes each property optional and turns each leaf property into any, allowing for type overrides by narrowing any. */
[P in keyof T]?: T[P] extends AnyObject ? DeepPartialAny<T[P]> : any
}
참고: type은 단지 type 힌트를 위한 것이지만 완벽합니다. 기술적으로, 이 유형의 논리는 리프 노드를 객체로 대체하고 그 반대도 가능하지만, 이와 같은 오류가 있는 플랫 프리미티브를 재정의할 때 불평할 것이다.
Type 'number' has no properties in common with type 'DeepPartialAny<{ a: string; }>'
그러나 오류를 안전하게 무시하거나 제약 조건을 모두 제거할 수 있습니다. 결과 유형이 올바르게 계산됩니다.
예
type ModifyDeep<A, B extends DeepPartialAny<A>> = {
[K in keyof A | keyof B]:
K extends keyof A
? K extends keyof B
? A[K] extends AnyObject
? B[K] extends AnyObject
? ModifyDeep<A[K], B[K]>
: B[K
: B[K
: A[K
: B[K
}
type AnyObject = Record<string, any>
type DeepPartialAny<T> = {
/** Makes each property optional and turns each leaf property into any, allowing for type overrides by narrowing any. */
[P in keyof T]?: T[P] extends AnyObject ? DeepPartialAny<T[P]> : any
}
interface Original {
a: {
a: string
b: { a: string }
c: { a: string }
}
b: string
c: { a: string }
}
interface Overrides {
a: {
a: { a: number } // <- overwrite string with object
b: number // <- overwrite object with number
c: { b: number } // <- add new child property
d: number // <- new primitive property
}
d: { a: number } // <- new object property
}
type ModifiedType = ModifyDeep<Original, Overrides>
interface ModifiedInterface extends ModifyDeep<Original, Overrides> {}
const t: ModifiedType = {
a: {
a: { a: number },
b: number,
c: { a: string, b: number },
d: number,
},
b: string,
c: { a: string },
d: { a: number },
}
declare const number: number
declare const string: string
declare const unknown: unknown
중첩된 인터페이스를 쉽게 재정의할 수 있도록 다음과 같은 유형을 만들었습니다.
export type DeepPartialAny<T> = {
[P in keyof T]?: T[P] extends Obj ? DeepPartialAny<T[P]> : any;
};
export type Override<A extends Obj, AOverride extends DeepPartialAny<A>> = { [K in keyof A]:
AOverride[K] extends never
? A[K]
: AOverride[K] extends Obj
? Override<A[K], AOverride[K]>
: AOverride[K]
};
그런 다음 다음과 같이 사용할 수 있습니다.
interface Foo {
Bar: {
Baz: string;
};
}
type Foo2 = Override<Foo, { Bar: { Baz: number } }>;
const bar: Foo2['Bar']['Baz'] = 1; // number;
더 나은 해결책은 아래의 수정된 유형의 답변을 사용하는 것입니다(펀 의도)을 사용하는 것입니다.
export type Modify<T, R extends Partial<T>> = Omit<T, keyof R> & R;
이렇게 하면 덮어쓰는 키가 원래 인터페이스에도 있는지 확인할 수 있으므로 원래 인터페이스가 이름을 변경할 경우 컴파일 시간 오류가 발생하고 이름도 변경해야 합니다.
설명:
다음 예를 들어보자.
interface OriginalInterface {
id: string
}
그리고 수정된 유형은 아래와 같습니다.
interface ModifiedInterface {
id: number
}
자, 미래에는 's'가 's'로 이름이 바뀌면 my type 유틸리티를 사용하면 다음과 같은 오류가 발생할 것입니다.
interface ModifiedInterface {
id: number // Type '{ geo_point1: GeoPoint | null; }' has no properties in common with type 'Partial<Address>'.ts(2559)
}
'개발하자' 카테고리의 다른 글
Flutter web asset images not displaying when deployed to web server (0) | 2022.11.13 |
---|---|
React with TypeScript를 사용하여 어린이를 특정 구성 요소로 제한할 수 있습니까? (0) | 2022.11.13 |
react native type 스크립트 'string'은 사용 중인 'never' 유형의 매개 변수에 할당할 수 없습니다. 탐색 (0) | 2022.11.12 |
Kubernetes 메트릭 서버 API (0) | 2022.11.12 |
유형스크립트 키-값 관계를 보존하는 Object.entries 유형 (0) | 2022.11.12 |