-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Creating types from values in array #28046
Comments
|
This is possible: function stringLiterals<T extends string>(...args: T[]): T[] { return args; }
type ElementType<T extends ReadonlyArray<unknown>> = T extends ReadonlyArray<infer ElementType> ? ElementType : never;
const values = stringLiterals('A', 'B');
type Foo = ElementType<typeof values>;
const v1: Foo = 'A' // This should work
const v2: Foo = 'D' // This should give me an error since 'D' doesn't exist in values Definitely not clear how to do this though. #27179 is related. |
That’s still using information known statically by the compiler though; at that point I don’t understand what the advantage is over just saying |
@fatcerberus It's useful to avoid repeating information -- if you just write |
Where are we on this, now ? Like @andy-ms said it would be really useful to avoid repeating information manually. |
Building on @andy-ms's answer, and using const assertions introduced in typescript 3.4, it's now possible to do something like this
|
This issue has been marked as 'Question' and has seen no recent activity. It has been automatically closed for house-keeping purposes. If you're still waiting on a response, questions are usually better suited to stackoverflow. |
in [email protected] and above. solve it like this export const type = <const>[
'room',
'room_with_gifter',
'user_send'
];
export interface Activity {
id?: string;
type: typeof type[number];
} |
Instead of this: export const items = <const>[
'room',
'room_with_gifter',
'user_send'
];
export interface Activity {
id?: string;
type: typeof items[number];
} You can do this: export const items = [
'room',
'room_with_gifter',
'user_send'
] as const;
export type Item = typeof items;
export interface Activity {
id?: string;
type: Item;
} Really don't like using |
Now what if I have this in a class? class Class {
const list = <const>[
'room',
'room_with_gifter',
'user_send'
];
const withType: typeof list[number];
} Does not work. I also cannot do |
@vegerot You can't use |
@7kms My bad. I copied and pasted too much. What I meant to say is class Class {
private list = <const>[
'room',
'room_with_gifter',
'user_send'
];
private withType: typeof list[number];
// OR
private withType2: typeof this.list[number];
} etc. all do not work. |
class Class {
private list = [
"room",
"room_with_gifter",
"user_send"
] as const
private withType: Class["list"][number]
} @vegerot How about this? |
@eyalch that's awesome! Thank you. I thought the solution would involve |
@vegerot Sure, I believe it's an "Index type". Here it is in the Handbook: https://www.typescriptlang.org/docs/handbook/advanced-types.html#index-types Glad I could help! |
Hey %username%, if |
const animals = ['cat', 'dog', 'mouse'] as const
type Animal = typeof animals[number]
// type Animal = 'cat' | 'dog' | 'mouse' |
Not sure why this works (maybe someone can help me understand), but this seems to work great for me: const expectedValues = {
headlines: {
signUpSelection: 'Create an account',
emailSignUp: 'Sign up (for free)',
logInSelection: 'Log into your account',
emailLogIn: 'Welcome back!',
checkout: 'Add a payment method',
},
};
type SectionName = keyof typeof expectedValues.headlines; |
@zeckdude I think you mean const expectedValues = {
headlines: {
signUpSelection: 'Create an account',
emailSignUp: 'Sign up (for free)',
logInSelection: 'Log into your account',
emailLogIn: 'Welcome back!',
checkout: 'Add a payment method',
},
} as const;
type SectionName = keyof typeof expectedValues.headlines; |
What if we want to use these as object keys? export const weekdays = [
'sunday',
'monday',
'tuesday',
'wednesday',
'thursday',
'friday',
'saturday'
] as const
export type WeekdayName = typeof weekdays
// This causes the error:
// Type 'readonly ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"]' does not satisfy the constraint 'string | number | symbol'
const WeekDayObj: Record<WeekdayName, any> = {
} These are string types but it seems that TS doesn't recognize this for the purposes of creating object keys. |
@matthew-dean |
Desired:What about the ability of inferring from an argument? const myFunc = <T extends readonly unknown[]>(options: T, currentOption: T[number]) => {
// ...
}
myFunc(['foo', 'bar', 'baz'], 'bar') // ok
myFunc(['foo', 'bar', 'baz'], 'qux') // error Currently it's not possible since Workaround:So the following usage works: const options = ['foo', 'bar', 'baz'] as const
myFunc(options, 'bar') // ok
myFunc(options, 'qux') // error |
Similar to @jniac example, my use case is more like interface TabsProp<T extends string[]> {
tabs: T
selected: OneOf<T>
onSelect: (tab: OneOf<T>) => void
} I currently have no workaround |
@xxRockOnxx Try this: import * as React from 'react';
interface TabsProp<T extends string> {
tabs: T[]
selected: ExcludeFromTypeInference<T>;
onSelect: (tab: ExcludeFromTypeInference<T>) => void
}
/**
* @see https://github.com/microsoft/TypeScript/issues/14829#issuecomment-504042546
*/
type ExcludeFromTypeInference<T> = [T][T extends any ? 0 : never];
declare class MyComponent<T extends string> extends React.Component<TabsProp<T>> {};
<MyComponent tabs={['foo', 'bar']} selected={'foo'} onSelect={tab => {
tab === 'foo' || tab === 'bar';
}} /> |
Huh, I was expecting this to be a request for a feature where, starting with an expression like ["foo", "bar"] you could request a "refactor" or something that would generate something equivalent to: type NewType =
|"foo"
|"bar" (where NewType would be selected so you could type the name you actually want), |
EDIT: I see ORIGINAL: Not sure if this helps, but to convert a tuple to a union type its sufficient to do: const weekdayNames = [
"monday",
"tuesday"
/* ect */
] as const
// Gives "monday" | "tuesday"
type WeekdayNames = typeof weekdayNames[Exclude<keyof typeof weekdayNames, keyof Array>] |
This is how to do it in late 2023: const animals = ['cat', 'dog', 'mouse'] as const
type Animal = typeof animals[number]
// type Animal = 'cat' | 'dog' | 'mouse' from: https://steveholgado.com/typescript-types-from-arrays/ |
I got it to work by putting |
TypeScript Version: 3.0.3
Search Terms: Type based on values in array
Is there a current or planned feature to create a type from strings in an array?
Code
Similar to how
keyof
works:Related Issues: #20965
Link to playground http://www.typescriptlang.org/play/#src=let%20vals1%20%3D%20%5B'A'%2C%20'B'%5D%0D%0Atype%20Foo1%20%3D%20OneOf%3Cvals1%3E%20%2F%2F%20Is%20there%20a%20way%20of%20doing%20this%3F%0D%0A%0D%0Alet%20v1%3A%20Foo1%20%3D%20'A'%20%2F%2F%20This%20should%20work%0D%0Alet%20v2%3A%20Foo1%20%3D%20'D'%20%2F%2F%20This%20should%20give%20me%20an%20error%20since%20'D'%20doesn't%20exist%20in%20values%0D%0A%0D%0Alet%20vals2%20%3D%20%7B%0D%0A%20%20A%3A%20'A'%2C%0D%0A%20%20B%3A%20'B'%0D%0A%7D%0D%0Atype%20Foo2%20%3D%20keyof%20typeof%20vals2%0D%0Alet%20v3%3A%20Foo2%20%3D%20'A'%0D%0Alet%20v4%3A%20Foo2%20%3D%20'D'%20%2F%2F%20Type%20'%22D%22'%20is%20not%20assignable%20to%20type%20'%22A%22%20%7C%20%22B%22'
The text was updated successfully, but these errors were encountered: