-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Feature request: Allow index types to be subtypes of string #13285
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
The type system can not guarantee that indexing into If i understand correctly you really do not need function updateIds<K extends string>(
obj: Record<K, string>,
idFields: K[],
idMapping: { [oldId: string]: string }
): Record<K, string> {
for (const idField of idFields) {
const newId = idMapping[obj[idField]]; // string
if (newId) {
obj[idField] = newId; // string
}
}
return obj;
}
updateIds({ id: /not a string/ }, ['id'], { 'old': 'new' }) // Error
updateIds({id: "strign", bar: "string" }, ['id', "bar"], {'old': 'new'}). // OK |
That almost works. But it constrains all the values of the object to be strings, which I don't want to do. Only the updateIds({id: 'old', b: 123}, 'id', {'old': 'new'})
|
I see. you really need the function updateIds<T extends { [x: string]: string }, K extends keyof T>(
obj: T,
key: K,
stringMap: { [oldId: string]: string }
) {
var x = obj[key];
stringMap[x]; // Should be OK.
} |
@mhegazy is that right? is |
@danvk With #13338 the following compiles with no errors: function updateIds<T extends Record<K, string>, K extends string>(
obj: T,
idFields: K[],
idMapping: { [oldId: string]: string }
): Record<K, string> {
for (const idField of idFields) {
const newId = idMapping[obj[idField]];
if (newId) {
obj[idField] = newId;
}
}
return obj;
} |
Thanks, @ahejlsberg. Keep up the great work! |
wouldn't it be better for |
@danvk In #28965 we are tightening up some rules related to your example. I suggest you change it to the following, which is more correct (see comments in #28965 for why the type annotation is necessary): function updateIds<T extends Record<K, string>, K extends string>(
obj: T,
idFields: K[],
idMapping: Partial<Record<T[K], T[K]>>
): Record<K, string> {
for (const idField of idFields) {
const newId: T[K] | undefined = idMapping[obj[idField]];
if (newId) {
obj[idField] = newId;
}
}
return obj;
} |
See this example from a medium post on mapped types.
I have a function
updateIds
which runs some subset of properties on an object through a mapping:This function is simple to implement but not entirely straightforward to type. Here's a version using
keyof
:The problem here is that
obj[idField]
has a type ofT[keyof T]
whereas it really needs to have a type ofstring
. I'd like the type system to require thatT[k] = string
for all the fields passed in the array.I don't believe there's any way to do this directly (please tell me if I'm wrong!)
One thought was to use a second type parameter for the property list:
But this gives the error
An index signature parameter type must be 'string' or 'number'.
If the index signature parameter could instead be a subtype of string (e.g."from" | "to"
) then I think this would work.TypeScript Version: 2.1.4
Code
Expected behavior:
I'd like this to be rejected since the
id
field doesn't have a string type.Actual behavior:
I don't have a way to enforce this through the type system.
The text was updated successfully, but these errors were encountered: