Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit 7a619a3

Browse files
committed
Simplify keyof
1 parent 9f11f3f commit 7a619a3

File tree

1 file changed

+26
-38
lines changed

1 file changed

+26
-38
lines changed

pages/release notes/TypeScript 2.1.md

Lines changed: 26 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
# `keyof` and Lookup Types
22

3-
Many libraries take advantage of the fact that objects are (for the most part) just a map of strings to values.
4-
Given what TypeScript knows about each value's properties, there's a set of known strings (or keys) that you can use for lookups.
3+
In JavaScript it is fairly common to have APIs that expect property names as parameters, but so far it hasn't been possible to express the type relationships that occur in those APIs.
54

6-
That's where the `keyof` operator comes in.
5+
Enter Index Type Query or `keysof`;
6+
An indexed type query `keyof T` yields the type of permitted property names for `T`.
7+
A `keyof T` type is considered a subtype of `string`.
8+
9+
##### Example
710

811
```ts
912
interface Person {
@@ -12,58 +15,43 @@ interface Person {
1215
location: string;
1316
}
1417

15-
let propName: keyof Person;
16-
```
17-
18-
`keyof Person` is equivalent to having written out
19-
20-
```ts
21-
let propName: "name" | "age" | "location";
18+
type K1 = keyof Person; // "name" | "age" | "location"
19+
type K2 = keyof Person[]; // "length" | "push" | "pop" | "concat" | ...
20+
type K3 = keyof { [x: string]: Person }; // string
2221
```
2322

24-
This `keyof` operator is called an *index type query*.
25-
It's like a query for keys on object types, the same way that `typeof` can be used as a query for types on values.
26-
2723
The dual of this is *indexed access types*, also called *lookup types*.
2824
Syntactically, they look exactly like an element access, but are written as types:
2925

30-
```ts
31-
interface Person {
32-
name: string;
33-
age: number;
34-
location: string;
35-
}
36-
37-
let a: Person["age"];
38-
```
39-
40-
This is the same as saying that `a` gets the type of the `name` property in `Person`.
41-
In other words:
26+
##### Example
4227

4328
```ts
44-
let a: number;
29+
type P1 = Person["name"]; // string
30+
type P2 = Person["name" | "age"]; // string | number
31+
type P3 = string["charAt"]; // (pos: number) => string
32+
type P4 = string[]["push"]; // (...items: string[]) => number
33+
type P5 = string[][0]; // string
4534
```
4635

47-
When indexing with a union of literal types, the operator will look up each property and union the respective types together.
36+
You can use this pattern with other parts of the type system to get type-safe lookups.
4837

4938
```ts
50-
// Equivalent to the type 'string | number'
51-
let nameOrAge: Person["name" | "age"];
52-
```
53-
54-
You can use this pattern with other parts of the type system to get type-safe lookups, which is great if you use Ember or other frameworks like it.
39+
function getProperty<T, K extends keyof T>(obj: T, key: K) {
40+
return obj[key]; // Inferred type is T[K]
41+
}
5542

56-
```ts
57-
function get<T, K extends keyof T>(obj: T, propertyName: K): T[K] {
58-
return obj[propertyName];
43+
function setProperty<T, K extends keyof T>(obj: T, key: K, value: T[K]) {
44+
obj[key] = value;
5945
}
6046

6147
let x = { foo: 10, bar: "hello!" };
6248

63-
let foo = get(x, "foo"); // has type 'number'
64-
let bar = get(x, "bar"); // has type 'string'
49+
let foo = getProperty(x, "foo"); // number
50+
let bar = getProperty(x, "bar"); // string
51+
52+
let oops = getProperty(x, "wargarbl"); // Error! "wargarbl" is not "foo" | "bar"
6553

66-
let oops = get(x, "wargarbl"); // error!
54+
setProperty(x, "foo", "string"); // Error!, string expected number
6755
```
6856

6957
# Mapped Types

0 commit comments

Comments
 (0)