-
Notifications
You must be signed in to change notification settings - Fork 0
Chapter 10 #10
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
base: initial
Are you sure you want to change the base?
Chapter 10 #10
Conversation
getAlbumDetails(album, "producer"); | ||
``` | ||
|
||
`keyof` is an important building block when creating new types from existing types. We'll see later how we can use it with `as const` to build our own type-safe enums. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it might be good to call out those 2 gotchas:
const oops: keyof { concrete: "foo"; [k: string]: unknown } = "whatever";
const test: keyof { [k: string]: unknown } = 42;
// ^? | ||
``` | ||
|
||
This is a more concise way to achieve the same result. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you could mention here that the index type gets distributed over the object type in this case
|
||
This solution makes the test pass, but it doesn't scale well. If the `programModes` array were to change, we would need to update the `AllPrograms` type manually. | ||
|
||
Instead, we can use the `number` type as the argument to the indexed access type to represent all possible index values: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's worth mentioning that it works like that because tuples are... arrays. We can have fixed-size tuples like:
type Tup = [string, number]
So one could imagine that we could only access this with 0
or 1
but to make tuples more practical they also have a numeric index signature that is a union of all possible property types here. And since a numeric index signature is there (just like on array types) it's permitted to use number
to index into them.
This introduces unsoundness in scenarios like this:
function test(tup: [string, number], index: number) {
const result = tup[index]
// ^?
}
test(['foo', 42], 5);
This could be seen as odd, the index signature isn't used when TS knows the exact number we are using for indexing... but as soon as we just introduce a little bit of indirection to lose the literal type it becomes fine with it:
const tup = ['foo', 42] as const
tup[5] // error
let num = 5
tup[num] // ok
It's a side-step from the type theory with the aim to make the language more approachable and useful and to allow for common patterns (even if they sometimes might bite back)
```typescript | ||
type Price = SellAlbumParams[1]; // number | ||
``` | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
an extra example here could also who how useful it might be when building layers of functions:
function inner(a: string, b: number) {}
function outer(extra: boolean, ...args: Parameters<typeof inner>) {}
outer;
// ^?
type Artist = Exclude<Album["artist"], null | undefined>; | ||
``` | ||
|
||
But `NonNullable` is more explicit and easier to read. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be good to call out that NonNullable
today is defined as T & {}
and that's because {}
means exactly that: a non nullable value, something on which you can access properties. 'foo'.whatever
while weird and a type error on its own... it's a not a runtime error, you simply get undefined
back from this. The same can't be said about (null).whatever
```typescript | ||
type Example = "a" | "b" | 1 | 2 | true | false; | ||
|
||
type Strings = Extract<Example, string>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a powerful way to do such filtering (especially on generic level) is to use... intersections :) this could be a section of its own in this whole deriving types chapter. The example above can be simply rewritten as follows:
type Strings = Example & string;
No description provided.