типизация через Record не совместима с конкретным ключом?

Рейтинг: 2Ответов: 2Опубликовано: 18.03.2023

как решить данную ситуацию? Хочется получить интерфейс в котором есть одни единственный ключь типо number, и много других типо boolean как вариант;

Property 'some' of type 'number' is not assignable to 'string' index type 'boolean'

type TType = Record<string, boolean>;

interface IProps extends TType {
   some?: number;
}

вариант с type TType = Record<string, boolean | number>; не подходит так как единственный тип с number это ключь some

Ответы

▲ 2Принят

Желаемый тип можно объявить так:

type IProps = {
  some?: number
} & {
  [key in string]?: key extends "some" ? number : boolean 
}

После этого переменные такого типа можно полноценно использовать.

Но есть проблема: присвоить переменной этого типа литеральный объект с полем some, отличным от undefined, тайпскрипт без явного приведения не позволит. А вот поменять значение поля уже существующей переменной можно без проблем.


Однако, по названию у меня сложилось впечатление, что речь о реакт-компонентах, а там можно нахимичить с дженериками: песочница

import React from 'react';

type Props<K extends string> = {
  some?: number
} & {
  [key in Exclude<K, "some">]: boolean
}

function Smth<T>(props: T & Props<string & keyof T>) {
  return null
}

function App() {
  return (
    <>
      <Smth />
      <Smth some={42} />
      <Smth qqq={true} />
      <Smth some={42} qqq={true} />
    </>
  )
}
▲ -1

Да, проблема в том, что типизация через Record<string, boolean> не совместима с конкретным ключом some.

Одно из возможных решений - использовать объединение типов с помощью "|". Таким образом, можно задать тип IProps следующим образом:

type TType = Record<string, boolean>;

interface IProps extends TType {
   some?: number;
   [key: string]: boolean | number | undefined;
}

Теперь IProps содержит ключ some с типом number, а также другие ключи с типом boolean или number, которые могут быть добавлены в объект.

Такой интерфейс позволяет создать объект со свойством some типа number и другими свойствами типа boolean:

const props: IProps = {
   some: 42,
   flag1: true,
   flag2: false,
   flag3: undefined,
};