5

Переопределение типа свойства интерфейса, определённого в файле d.ts TypeScript

34

Есть ли способ изменить тип свойства интерфейса, определенного в файле *.d.ts в TypeScript?

Например, в файле x.d.ts интерфейс определен так:

interface A {
  property: number;
}

Я хочу изменить его в своих TypeScript файлах на:

interface A {
  property: Object;
}

Или даже так:

interface B extends A {
  property: Object;
}

Сработает ли такой подход? У меня не получилось этого сделать на моей системе. Хотелось бы подтвердить, возможно ли это вообще?

5 ответ(ов)

0

Краткий ответ для ленивых, как я:

type Overrided = Omit<YourInterface, 'overrideField'> & { overrideField: <тип> }; 
interface Overrided extends Omit<YourInterface, 'overrideField'> {
  overrideField: <тип>;
}

Эти примеры иллюстрируют, как создать новый тип или интерфейс, исключив поле overrideField из YourInterface и добавив его с новым типом.

0

Расширяя ответ @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;
}

// переопределяем имя так, чтобы это был string | number
type B = Merge<A, {
    name: string | number;
    favorite?: boolean;
}>;

let one: A = {
    name: 'asdf',
    color: 'blue'
};

// A может быть преобразован в B, так как типы совместимы
let two: B = one;

let three: B = {
    name: 1
};

three.name = 'Bee';
three.favorite = true;
three.color = 'green';

// B не может быть преобразован в A, так как тип name (string | number) несовместим
// с A, даже если значение — это строка
// Ошибка: Type {...} is not assignable to type A
let four: A = three;

В этом примере у нас есть два типа: A и B, где тип B объединяет свойства A и добавляет или изменяет некоторые из них. Таким образом, вы можете использовать такой подход для более гибкого управления типами в TypeScript.

0

Чтобы исключить свойство из интерфейса при его расширении, можно воспользоваться утилитой TypeScript Omit. В вашем примере вы хотите расширить интерфейс A, исключив свойство a, и добавить его с другим типом в интерфейс B. Вот как это можно сделать:

interface A {
  a: number;
  b: number;
}

interface B extends Omit<A, 'a'> {
  a: boolean;
}

В этом случае интерфейс B наследует все свойства интерфейса A, за исключением свойства a, которое заменяется на свойство a типа boolean. Таким образом, в интерфейсе B будет свойство b типа number и новое свойство a типа boolean.

0

Чтобы создать тип, который позволяет легко переопределять вложенные интерфейсы, я разработал следующий код:

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;

Таким образом, вы можете переопределять типы вложенных свойств в интерфейсах, сохраняя гибкость и типобезопасность.

0

Порой предложенные решения могут не сработать. Это может произойти в следующем случае.

interface A {
    [k: string]: string;
}

interface B extends A {}

type C = Omit<B, 'x'> & { x: number }

В этом примере тип C будет иметь x со строковым типом в любом случае. Это может быть актуально, если вы хотите переопределить, например, тип process.env.

Чтобы исправить эту проблему, необходимо переопределить интерфейс A следующим образом, удаляя ключи более строго:

interface C {
    x: number;
}

type ExcludeKeys<Type, Keys> = {
    [Property in keyof Type as Exclude<Property, Keys>]: Type[Property];
};

type AA = ExcludeKeys<B, keyof C> & C;

Таким образом, с помощью утилиты типа ExcludeKeys мы можем более строго исключать нужные ключи и добиться желаемого результата в типе AA.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь