TypeScript Version: 2.2.0
Code with unexpected type error:
export function set<T, K extends keyof T>(obj: T, key: K, value: T[K]) {
return Object.assign(obj, {
[key]: value,
});
}
Expected behavior:
No type errors because K
should is a subtype of keyof T
. It works if key: keyof T
and even key: K & keyof T
.
Actual behavior:
Type error:
A computed property name must be of type 'string', 'number', 'symbol', or 'any'.
I was almost desperate trying to get similar code working:
class Options<T extends object, K extends keyof T>
{
[key:K]:T[K];
constructor(value:T)
{
Object.assign(this, value);
}
}
Also I wonder, is it possible to avoid declaring second type parameter (K
)?
@kemsky You could simply replace all occurrences of K
with keyof T
.
Here there is another example that fails with the same error
const changeValue = <K extends keyof State> (key: K, value: string) => {
return (prevState: State, props: Props): Pick<State, K> => {
return {
[key]: value
}
}
}
In addition to the error @altschuler gets, I get:
Type '{ [x: string]: string; }' is not assignable to type 'Pick<State, K>'
State:
interface State {
foo: string
}
Bump, this still happens with 2.3.4, are there any plans to fix/implement this? cc @RyanCavanaugh (You're the only collaborator to interact with this issue)
The error message should be checking the apparent type of key
. The apparent type would correctly resolve to the type parameter's K
's constraint, which is string-like, instead of the type parameter K
itself, which is not itself string-like.
Fixed in #17404. The apparent type turned out not be quite right because that also converts string
to String
and so on. Instead I just get the type parameter's constraint and use that if there is one.
The error from @kevinjhanna's comment is still occurring in TS 2.5 and above. Is this intended?
Yes, this needs @rbuckton's PR for binding of dynamic names to work: #15473
^ @sandersn
So, that error from @kevinjhanna's comment is still occurring in TS 2.9. Is this intended? Does it need a new issue?
Hi,
I also have a problem that may be realated to this issue (I'm using TS 2.9.2):
https://stackoverflow.com/a/50929895/2292481
Hello,
This has been implemented now but isn't in the type-system if you wanted to strongly type usages of computed properties. For example, here I'm trying to use mapped types with computed properties (I've simplified the following code/example so the purpose of the function might not make much sense practically but you can see the idea).
merge (target, source) {
Object.keys(source).forEach(key => {
Object.assign(target, { [key]: {} });
});
}
And attempting to strongly typing this in an ambient module (for a JS framework) and it's currently not possible. For example:
declare function merge<Target extends {}, Source extends {}>(target: Target, source: Source): Target extends object ?
Source extends object ? {
[Key in keyof Source]: Target & { [Key]: object } // Error here at [Key] - "'Key' only refers to a type, but is being used as a value here."
} : never
: Target;
This is still occurring in TS v3.3:
export async function* pick<TItem, TKey extends keyof TItem>(
iterable: Iterable<TItem> | AsyncIterable<TItem>,
...keys: TKey[]
): AsyncIterable<Pick<TItem, TKey>> {
for await (const item of iterable) {
yield {
[key in keys]: item[key]
};
}
}
Error: A computed property name must be of type 'string', 'number', 'symbol', or 'any'.
How to fix this TS kind error ?????
@towry You should be able to fix that by explicitly defining the type of the indexer as a string (number, symbol or 'any') as per the error message:
let variable = {
[a: string]: 123
};
As far as I can tell, typescript currently can't process keyof
a generic when used within a computed property, and instead always converts it to string
:
class Wrapper<T> {
Inner<K extends keyof T>(key: K, value: T[K]) {
// All good
const x: Partial<T> = {};
x[key] = value;
// Type '{ [x: string]: T[K]; }' is not assignable to type 'Partial<T>'.
const y: Partial<T> = {
[key]: value,
};
}
}
https://www.typescriptlang.org/play/index.html#code/MYGwhgzhAEDqBOYAOSCm8A8AVAfNA3gFDQnQCSAdhehgNLSoAeALqhQCYwDWqAngPYAzaLgAUPXgC5otADTQAbmBABXVNKwBtWgF0AlAWKljAehNx+8LhCPGSwfhQjNojaQAUw8ZgEtl2PABeAgBfAG5bO0ZNCR1oYKVVVAjI03MsXjRoAHJ8aE03aGd4HwoAcx0NbR0w6BDs6B8YCn4XSAgfMoowACMQVGhmfkHMgezPbz8QAOyAOlTSBycXKWgJ339ceMM7XfzY6US1WQWScMiQwhCgA
You can of course just as any
them to force it to work, but that's a pretty garbage solution.
@davidfarinha
Still a problem in 3.6 :(
REOOOOPEEEEN TAAASK!!!!!
Most helpful comment
This is still occurring in TS v3.3:
Error: A computed property name must be of type 'string', 'number', 'symbol', or 'any'.