Следующий код:
type K = "foo" | "bar";
interface SomeType {
[prop: K]: any;
}
Выдает это сообщение об ошибке:
An index signature parameter type cannot be a union type. Consider using a mapped object type instead.
Никто не знает, что такое сопоставленные типы объектов, поэтому давайте быстро исправим
extends
если содержащий тип объекта является интерфейсом и имеет любые предложения extends
Никто не знает, что такое сопоставленные типы объектов, поэтому давайте быстро исправим
+1, просто пришел сюда, потому что я ожидал, что 2.9 будет поддерживать союзы в качестве индексных подписей для вашего примера кода. Я думаю, что это давно желанная функция: # 5683, # 16760 и т. Д.
Ты можешь это сделать:
type Foo = 'a' | 'b';
type Bar = {[key in Foo]: any};
Хотя Bar
не имеет подписи индекса (т. Е. Вы не можете выполнить (obj as Bar)[value as Foo]
).
Изменить: хотя, если бы вы могли сделать предупреждение не проблемой, я был бы бесконечно благодарен!
я бы хотел поработать над этим: смеется:
Перемещает другие элементы в отдельный тип объекта, который комбинируется с типом пересечения
что делать, если объектный тип содержит класс?
Могу только представить, что это интерфейс
так что должен делать код после быстрого исправления?
type K = "1" | "2"
class SomeType {
a = 1;
[prop: K]: any;
}
так что должен делать код после быстрого исправления?
Я бы сказал, это поправимо ..
@mhegazy Я использую 3.0.0-rc и все еще получаю ту же ошибку, что и изначально. Ожидается ли это?
Я использую 3.0.0-rc и по-прежнему получаю ту же ошибку, что и изначально. Ожидается ли это?
да. ошибка правильная. эта проблема отслеживалась добавлением быстрого исправления для нее, то есть светлой мякоти рядом с сообщением об ошибке.
в версиях 2.9.1 и vscode отсутствуют действия кода
@ThaJay Мы не будем обратно , попробуйте установить более новую версию.
Очевидно. Прошу прощения за то, что сначала не проверил график, просто предположил, что он достаточно новый. Новое в ts. Проверю с версией 3.
как это описать:
function createRequestTypes(base){
return ['REQUEST', 'SUCCESS', 'FAILURE'].reduce((acc, type) => {
acc[type] = `${base}_${type}`
return acc
}, {})
}
const user = createRequestTypes('USER')
console.log(user.REQUEST) // error
// just string? like:
interface IRequestType: {[key: string]: string}
Я пробовал ниже, все не удалось:
type requestStatus = 'REQUEST' | 'SUCCESS' | 'FAILURE'
type requestTypes = {
[key in requestStatus]: string
}
// or
interface IRequestTypes {[key: keyType]: string}
// or even
type requestTypes = {
FAILURE: string,
SUCCESS: string,
REQUEST: string
}
@maicWorkGithub, вот и все:
const user = createRequestTypes('USER')
console.log(user.REQUEST)
function createRequestTypes(base:string):requestTypes {
const result : requestTypes = {}
const arr : requestStatus[] = ['REQUEST', 'SUCCESS', 'FAILURE']
return arr.reduce((acc, type) => {
acc[type] = `${base}_${type}`
return acc
}, result)
}
type requestStatus = 'REQUEST' | 'SUCCESS' | 'FAILURE'
type requestTypes = { [key in requestStatus]?: string }
@ihorskyi Спасибо !!
Просто любопытно, почему type
работает, а interface
- нет. Кто-нибудь может объяснить, пожалуйста? В чем причина такого ограничения (или функции?) interface
.
type Foo = 'a' | 'b';
type Bar = {[key in Foo]: any}; // ok
interface Baz {[key in Foo]: any} // =>
// A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type.ts(1169)
// A computed property name must be of type 'string', 'number', 'symbol', or 'any'.ts(2464)
// 'Foo' only refers to a type, but is being used as a value here.ts(2693)
Это было удивительное автоматическое исправление. Спасибо за то, что реализовали! :)
То же и для классов.
Ты можешь это сделать:
type Foo = 'a' | 'b'; type Bar = {[key in Foo]: any};
Хотя
Bar
не имеет подписи индекса (т. Е. Вы не можете выполнить(obj as Bar)[value as Foo]
).Изменить: хотя, если бы вы могли сделать предупреждение не проблемой, я был бы бесконечно благодарен!
Вместо этого используйте Record
!
type Foo = 'a' | 'b'
type Bar = Record<Foo, any>
Чтобы добавить еще один пример этого с использованием класса ...
class Foo {
a: string;
b: string;
}
type Bar = {[key in keyof Foo]: any};
Нет слов, просто мем:
https://media1.tenor.com/images/23d9d746fc87b3a93298af43dae21f6a/tenor.gif
:)
еще лучше при использовании частичного
type A = 'x' | 'y' | 'z';
type M = Partial<{
[key in A]: boolean
}>;
Никто не знает, что такое сопоставленные типы объектов, поэтому давайте быстро исправим
@DanielRosenwasser
Почему сообщение об ошибке не может предложить ответ, например, покажите быстрый пример с использованием сопоставленного типа - это будет всего пара строк кода, который будет соответствовать средней длине сообщений об ошибках TypeScript: trollface:
Кто-нибудь знает, можно ли сказать, что интерфейс, который использует тип или перечисление в качестве ключа, может принимать только одно свойство?
Например подпись вроде этой: { <field>: { <and|or|xor>: <int> } }
взято из
export enum BitwiseOperator {
and = "and",
or = "or",
xor = "xor",
}
export type BitwiseCondition = {
[key in BitwiseOperator]?: number;
}
Затем при его использовании я хотел бы убедиться, что переменная, которая определяется интерфейсом, имеет только одно свойство.
const query: BitwiseCondition = {
and: 5,
or: 6 // raise a ts error
};
@ b4dnewz Вы не можете сделать это в Typescript. Обходной путь: https://github.com/Microsoft/TypeScript/issues/10575
@ b4dnewz , если вам нужен только 1 объект, почему бы не сделать это так?
export enum BitwiseOperator {
and = "and",
or = "or",
xor = "xor",
}
export type BitwiseCondition = {
operator: BitwiseOperator;
value: number;
}
@benwinding, к сожалению, возвращенная форма отличается от того, что ожидает mongodb
@apieceofbart спасибо за предложение, я изучил его, немного избыточно с точки зрения интерфейсов, но может работать, я не уверен, что я его сейчас реализовал, поскольку это не имеет большого значения, если конечный пользователь попробует побитовое условие с двумя операторами, mongo все равно выдаст ошибку
Я стараюсь, чтобы определения монго-операторов были как можно более простыми, чтобы избежать головной боли 😁 возможно, в будущем будет добавлена соответствующая поддержка
@ b4dnewz достаточно честно,
Возможно, вы могли бы использовать более простой вариант:
export type BitwiseCondition =
| { or: number }
| { xor: number }
| { and: number }
Это самое близкое, что вы получите без особого дублирования
@ b4dnewz достаточно честно,
Возможно, вы могли бы использовать более простой вариант:
export type BitwiseCondition = | { or: number } | { xor: number } | { and: number }
Это самое близкое, что вы получите без особого дублирования
В этом примере это не приведет к ошибке:
const query: BitwiseCondition = {
and: 5,
or: 6 // raise a ts error
};
Я думал в этом весь смысл
@apieceofbart ,
В этом примере это не приведет к ошибке:
export type BitwiseCondition =
| { or: number }
| { xor: number }
| { and: number }
const query: BitwiseCondition = {
and: 5,
or: 6 // doesn't raise a ts error!
};
Вау! это странно: open_mouth: я этого не знал!
Похоже, что Typescript не поддерживает взаимоисключающие типы для объектов. Здесь также было предложение по языку: https://github.com/microsoft/TypeScript/issues/14094
Из этого ответа условных типов (самых сложных типов), но это не очень ...
/*
XOR boiler plate
*/
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
type XOR<T, U> = T | U extends object
? (Without<T, U> & U) | (Without<U, T> & T)
: T | U;
type XOR3<S, T, U> = XOR<S, XOR<T, U>>;
// Code start
export type BitwiseCondition = XOR3<
{ or: number },
{ xor: number },
{ and: number }
>;
const query1: BitwiseCondition = {
and: 5
};
const query: BitwiseCondition = {
and: 5,
or: 6 // raise a ts error
};
Если кто-то может сделать это красивее или лучше, пожалуйста, сделайте
@mvasin FWIW, это _показано_ для достижения того же результата, но я полностью согласен с тем, что это должно быть особенностью интерфейсов, как и для типов.
type Foo = 'a' | 'b';
type Bar = {
[key in Foo]: any
}
interface A extends Bar { }
class Wol implements A{
a: any;
b: any;
}
Для машинописного текста 3.5 кажется, что я должен сделать это:
export interface DataTableState {
columnStats: {[key in keyof DataTable]?:{}}
}
Это лучший способ сделать это?
Почему именно индексная подпись не может использовать перечисляемый тип? Сопоставленный тип почти делает то, что я хочу, но тогда TypeScript ожидает, что каждая строка из перечисления будет существовать как определенный ключ. На самом деле я не хочу утверждать, что каждый ключ существует, более того, если какие-либо ключи действительно существуют, они должны жить в перечислении.
Например для типа:
type MyType = {
[Key: 'foo' | 'bar' | 'zip']: number;
};
Это должно удовлетворить:
const x: MyType = {
foo: 1,
zip: 2
};
Хотя я мог бы просто установить другие ключи undefined для сопоставленного типа, я предпочитаю сделать ключи необязательными, но если они есть, значение не может быть неопределенным. Если я сделаю значения сопоставленных типов необязательными, код будет работать, но типы будут менее сильными.
еще лучше при использовании частичного
type A = 'x' | 'y' | 'z'; type M = Partial<{ [key in A]: boolean }>;
Благодаря!
Полезно, когда вам нужно определить тип, частично соответствующий словарю
«Частично» также можно использовать в записях:
type Foo = 'a' | 'b';
let foo1: Record<Foo, number> = { a: 1, b: 2 };
let foo2: Partial<Record<Foo, number>> = { a: 1 };
Я случайно захожу на эту страницу GitHub примерно раз в месяц.
Мой последний очень простой:
interface ObjectLiteral {
[key: string | number]: any
}
export const mapToObjectLiteral = (map: Map<string|number, any>) =>
Array.from(map).reduce((objLit, [key, value]) => {
objLit[key] = value
return objLit
}, {} as ObjectLiteral)
Я могу прокрутить вверх и найти обходной путь, но просто хотел сообщить, что эта проблема часто возникает при повседневной работе в немного разных сценариях.
вот пример:
type MapKey = string | number;
type ObjectLiteral<T extends MapKey, V = any> = {
[P in T extends number ? string : T]: V;
};
export const mapToObjectLiteral = <T extends MapKey, V>(map: Map<T, V>) =>
Array.from(map).reduce((objLit, [key, value]) => {
objLit[key as keyof ObjectLiteral<T>] = value;
return objLit;
}, {} as ObjectLiteral<T, V>);
// how to make a better type of map ?
const m = new Map<1 | "foo", "a" | "b">();
m.set(1, "a");
m.set("foo", "b");
const o = mapToObjectLiteral(new Map(m));
console.log(o[1], o.foo); // just got an union type of every member of 'o'
https://github.com/microsoft/TypeScript/issues/24220#issuecomment -504285702
Чтобы добавить еще один пример этого с использованием класса ...
class Foo { a: string; b: string; } type Bar = {[key in keyof Foo]: any};
Очень полезно. Благодаря! 🚀
Самый полезный комментарий
Ты можешь это сделать:
Хотя
Bar
не имеет подписи индекса (т. Е. Вы не можете выполнить(obj as Bar)[value as Foo]
).Изменить: хотя, если бы вы могли сделать предупреждение не проблемой, я был бы бесконечно благодарен!