-
Notifications
You must be signed in to change notification settings - Fork 13.2k
Closed
Labels
Design NotesNotes from our design meetingsNotes from our design meetings
Description
keyof T and T[K]
Note about terminology
keyofis a type operator. Note, name change from Keysof type operator #10425 tokeyof; since the type name represents one value and not the whole value domain. this is inline with the other names of types e.g. we callnumberand notnumbers,- Henceforth, formal names of these type operators:
keyof T=> Index Type QueryT[K]=> Indexed Access Type
Details
keyof T
-
known properties and index signatures (
number | stringfor string indexers andnumberfor numeric indexers) -
Examples:
keyof { a: number, b:string}=>"a" | "b"keyof { [x: string] : number }=>string | numberkeyof { [x: number] : number }=>numberkeyof {}[]=>"toString" | "pop" |...| numberkeyof { a: number, b:string } | { a: number, c:string}=>"a"keyof { a: number, b:string } & { a: number, c:string}=>"a" | "b" | "c"
-
What about symbols?
- symbols not supported yet. we need to make symbols literal types first.
-
privateandprotected
A piece of trivia, accessing private and protected properties are allowed for index access todayclass C { private x; } let c: C; c.x; // not allowed c["x"]; // is allowed today
- should this apply to the new type operator:
ts type T = C["x"]; // OK or not? - for
nameofin C# does not do this either- it exists at run time
- against
- we should not carry past misdeeds in new features
- it exposes implementation details
- not valid for declaration emit, since we strip out the type
- Decision
keyof Tis public-only known properties, private and protected properties are not included
- should this apply to the new type operator:
T[K]
- only index with a type
Kparameter iff it is constraint to thekeyof T - this grantees that the output is type of a property
- can be used with literal types
class Thing {
name: string;
width: number;
}
type q1 = Thing["name"]; // string
type q2 = Thing["name" | "width"]; //string | number
type q3= Thing["name" | "foo"]; // Error "foo" is not a property on ThingPutting them together
function getProperty<T, K extends keyof T>(obj: T, key:K) {
return obj[key]; // T[K]
}
function setProperty<T, K extends keyof T>(obj: T, key:K, value: T[K]) {
obj[K] = value;
}
var thing: Thing;
var thingList: Thing[];
getPropeprty(thing, "foo") // Error
getPropeprty(thing, "name") // string
getPropeprty(thingList, 1) // Thing
getPropeprty(thingList, 1 + 2) // Thing
setPropoerty(thing, "name", "my name"); // OK
setPropoerty(thing, "name", 3); // ErrorIndex access unification
- The way we do
T[K]for a type should be the same as that for an expressiont[k]. - so
thing[condition ? "name" : "width"]; // should be string | numberIssues
Variance
Consider this:
setPropoerty(thing, condition? "name" : "width", "string"); - this is allowed today, but it is unsafe...
Keyof Tshould be a union for types of all properties for read, but an intersection for write. - This is the same behavior we have today for indexers anyways:
interface I {
a: number;
b: string;
[x: string] : number | string;
}
const k = condition? "a" : "b";
x[k] // number | string;
x[k] = "bar"; // allowed but not safe- We are getting close to the "safe variance" glass ceiling
- solving these all would need to add variance in the type system
- a readonly, writeonly, and readwrite types
- this applies to class properties, parameters, everything
- this would be a large braking change, and have to be done holistically
- the safer it would be the tighter it would be for users to use
Where we can land:
- For expressions, it would be an error i.e.
thing[condition ? "name" : "width"] = "bar"; /// Error, we know unsafe - but not for generic type argument
setProperty(thing, condition ? "name" : "width", "bar"); // OK Note about readonly:
- you can write a readonly propoerty using
setPropoerty. - there is not much we can do here. the time where this would be observed is at instantiation time, which is too late at that point to report errors.
- and again it goes back to variance, you need
readonly keyof Tandreadwrite keyof T.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
Design NotesNotes from our design meetingsNotes from our design meetings