Переопределение типа свойства интерфейса, определенного в файле Typescript d.ts
Есть ли способ изменить тип свойства интерфейса, определенный в *.d.ts
в машинописи?
например: интерфейс в xdts
определяется как
interface A {
property: number;
}
Я хочу изменить его в файлах машинописи, в которые я пишу
interface A {
property: Object;
}
или даже это будет работать
interface B extends A {
property: Object;
}
Будет ли этот подход работать? Это не сработало, когда я попробовал свою систему. Просто хотите подтвердить, если это вообще возможно?
Ответы
Ответ 1
Вы не можете изменить тип существующего свойства.
Вы можете добавить свойство:
interface A {
newProperty: any;
}
Но меняем тип существующего:
interface A {
property: any;
}
Приводит к ошибке:
Последующие объявления переменных должны иметь одинаковый тип. Переменная 'property' должна иметь тип 'number', но здесь имеет тип 'any'
Конечно, вы можете иметь свой собственный интерфейс, который расширяет существующий. В этом случае вы можете переопределить тип только на совместимый тип, например:
interface A {
x: string | number;
}
interface B extends A {
x: number;
}
Кстати, вам, вероятно, следует избегать использования Object
в качестве типа, вместо этого используйте тип any
.
В документах для any
типа говорится:
Любой тип - это мощный способ работы с существующим JavaScript, позволяющий постепенно включать и отключать проверку типов во время компиляции. Вы можете ожидать, что Object будет играть аналогичную роль, как и в других языках. Но переменные типа Object позволяют вам только присвоить им любое значение - вы не можете вызывать произвольные методы для них, даже те, которые действительно существуют:
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'.
Ответ 2
Я использую метод, который сначала фильтрует поля, а затем объединяет их.
ссылка Исключить свойство из типа
interface A {
x: string
}
export type B = Omit<A, 'x'> & { x: number };
для интерфейса:
interface A {
x: string
}
interface B extends Omit<A, 'x'> {
x: number
}
Ответ 3
type ModifiedType = Modify<OriginalType, {
a: number;
b: number;
}>
Вдохновленный решением ZSkycat extends Omit
, я придумал следующее:
type Modify<T, R> = Omit<T, keyof R> & R;
// before [email protected]
type Modify<T, R> = Pick<T, Exclude<keyof T, keyof R>> & R
Пример:
interface OriginalType {
a: string;
b: boolean;
c: number;
}
type ModifiedType = Modify<OriginalType , {
a: number;
b: number;
}>
// ModifiedType = { a: number; b: number; c: number; }
Шаг за шагом:
type R0 = Omit<T, 'a' | 'b'> // { c: number; }
type R1 = R0 & {a: number, b: number } // { a: number; b: boolean; 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: boolean; c: number; }
Ответ 4
Немного расширив ответ @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;
Ответ 5
Смешно, что я провожу день, расследуя возможность решить один и тот же случай. Я обнаружил, что это невозможно сделать так:
// 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;
}
Причина. Модуль может не знать обо всех доступных типах приложения. И это довольно скучный порт из всех, и делает такой код.
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;
}
Отключите глупое исключение, используя флаг @ts-ignore
, говоря нам, что мы делаем что-то неправильно. И смешно, что все работает так, как ожидалось.
В моем случае я уменьшаю вид видимости вида x
, это позволяет мне делать код более строгим. Например, у вас есть список из 100 свойств, и вы уменьшаете его до 10, чтобы избежать глупых ситуаций