You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
You can get valuesof arr with the indexed access type (typeof arr)[number], but you'll get string instead of "one" | "two" without an explicit type annotation. #10195 would help there though.
Reacted by David Skx, Rafael Kraut, Jarek Radosz, bk1012, Dave T. Johnson, Tomas Sandven, Dmitry Mazurok, Lou Cyx, Thomas, Mahmoud ElNaggar and 17 more
Thanks Daniel Rosenwasser (@DanielRosenwasser), #10195 would be helpful but ideally we would be able to do without indexed access types. What I was looking for was a way to express: "All keys in an object must be a value in an array".
Reacted by PaulHan, Deric Cain, Alfonso Valencia, Sam Becker, valerio, Jeffrey Brubaker and Roman Novák
Reacted by Theophilus Omoregbee, Oleg Artene, Antoine ESTEVE, Sarju, Jiri Spac, Ilya Sergeev, Valeriy Sotnikov, Edmundo Santos, Sebastián Balay, Fumiki and 34 more
Reacted by a.t., Lukas Bombach, Valentin Radu, Rubens Mariuzzo, paul-b, Samuel Bodin, Pau Colomé, Saúl de León Guerrero, Alaa Moucharrafie, Pasha and 2 more
bezreyhan I came across this issue while searching around for something else. I don't know if this will be useful to you two months later but I think this will do essentially what you want as long as you don't need to save the array in a variable beforehand:
functionfunctionGenerator<Textendsstring,U={[KinT]?: string}>(keys: T[]): (p: U)=>U{return(p: U)=>p}consttestFun=functionGenerator(['one','two'])testFun({one: '1'})// no errortestFun({two: '2'})// no errortestFun({three: '3'})// error as expected because 'three' is not a known property
If you do need the array in a variable, it looks like this will work:
functionliteralArray<Textendsstring>(array: T[]): T[]{returnarray}constarr=literalArray(['one','two'])consttestFun2=functionGenerator(arr)testFun2({one: '1'})// no errortestFun2({two: '2'})// no errortestFun2({three: '3'})// error as expected because 'three' is not a known property
Here is a link of those examples in the playground: Link
Reacted by Denis Sokolov, 楼教主, Zaku, Jan Olaf Martin, Glavin Wiechert, Peter Verswyvelen, James Kim, Andrey Shcherbinin, David Rosen, Patrick El-Hage and 26 more
Reacted by mulfyx, Isak Persson and Jacob Feliciani
Reacted by Glavin Wiechert, Peter Verswyvelen, James Kim, Andrey Shcherbinin, David López Pérez, Patrick El-Hage, Oleksii Shnyra, mulfyx, emmveqz, Kevin Wade and 4 more
Reacted by Bronley Plumb, Sam Becker and Jacob Feliciani
Using resolveJsonModule, would it be possible to get the type of a JSON array without explicitly declaring the type of the JSON module and losing typechecking on its data? I tried the ValuesOf approach but it seems like I would have to declare the type of my function argument explicitly.
Kevin Donnelly (@kpdonn) I find your solution very interesting.
Any idea how to have the same result with an array of object instead of an array of string ?
The following code passes typescript diagnostic. However, the last line should throw an error.
functionfunctionGenerator<Textends{name: string},U={[KinT['name']]?: string}>(keys: T[]): (p: U)=>U{returnp=>p;}consttestFun=functionGenerator([{name: 'one'},{name: 'two'}]);testFun({one: '1',two: '2'});// no errortestFun({two: '2'});// no errortestFun({three: '3'});// error expected but type diagnostic passes
Kevin Donnelly (@kpdonn) I find your solution very interesting.
Any idea how to have the same result with an array of object instead of an array of string ?
The following code passes typescript diagnostic. However, the last line should throw an error.
If anyone is interested, I found the solution of my problem:
functionfunctionGenerator<Vextendsstring,Textends{name: V},U={[KinT['name']]?: string}>(keys: T[]): (p: U)=>U{returnp=>p;}consttestFun=functionGenerator([{name: 'one'},{name: 'two'}]);testFun({one: '1',two: '2'});// no errortestFun({two: '2'});// no errortestFun({three: '3'});// throws an error
Reacted by Frederick Fogerty, Fernando Rojo and Vadim Kostin
export type Things = ReadonlyArray<{
readonly fieldA: number
readonly fieldB: string
readonly fieldC: string
...other fields
}>
type Thing = Things[number]
When I do that, type Thing has the correct type. Obviously you wouldn't want to do this by default, but I find myself in the situation where I have something generating array types, but sometimes I want functions to take a single value of that array and obviously I don't want to have to manually duplicate the type definition.
The above syntax is kind of weird, but it seems to do the job?
Reacted by PaulHan, xiao xin, Arthur R Longbottom, Marat Dyatko, Gabriel Meola, Jon Thompson, Juan Lapadula Plá, Matthias Kunnen, himStone, Serrulien and 117 more
Reacted by Orlando Del Aguila
Reacted by Etienne Martin, Nathan Nelson, Ayhan Yildiz, Adam, Sans X, Michael Yaworski, Adam Salma, Jonas, Francesco Belvedere, vtereshyn and 6 more
Reacted by Etienne Martin, Rafał Budzis, Alexander Springer, Andrzej, Sans X, Michael Yaworski, alexlemons, Adam Salma, Shinigami, Francesco Belvedere and 11 more
Reacted by Francesco Belvedere, Maged Mohamed, DaviDevMod, Cristian Perez, Matthew Miller and Orlando Del Aguila
Reacted by Francesco Belvedere, Damien Deloubes, Cristian Perez and Orlando Del Aguila
You need to decide whether label should be of type string or only allow the constants defined in the array, 'homepage' | 'team'. The two contradict each other. Just safely typing the array without being able to extract a type for label values would work like this, but I‘m not sure if it suits your usecase:
I'm trying to get a literal type from an operation on a literal type. I think the issue is K[number] will return a union type which has no understanding of order.
Daniel Nagy (@daniel-nagy)T[K[number]][] results in an array, but you want a tuple. You can keep the tuple type when you take advantage of mapped type support used like this: { [P in keyof T]: X } where T is the tuple. As far as I have understood, the keyof T is the tuple array index (since arrays in JS are just objects with indexes as keys), and this syntax builds a new tuple with the same indexes.
All together this nearly works as expected:
function getValues<T, K extends readonly (keyof T)[]>(object: T, keys: K): { [P in keyof K]: T[K[P]] } {
return keys.map(key => object[key]) as any
}
While the result type is now correctly [1, "three"], TypeScript shows an error: Type 'K[P]' cannot be used to index type 'T'.. I think this is a bug in TypeScript, maybe related to #21760 or #27413.
Here's a small workaround that fixes this error 🎉:
function getValues<T, K extends readonly (keyof T)[]>(object: T, keys: K): { [P in keyof K]: T[K[P] & keyof T] } {
return keys.map(key => object[key]) as any
}
// Option 0: Define type using objectconstsomeTypeExample={a: 1,b: 'str',c: 'foo'as'foo'|'bar'};typeSomeType0=typeofsomeTypeExample;// Option 1: If object stores different types (with disadvantages)typeSomeType={a: number;b: string;}consttypeVar: SomeType={a: 10,b: 'string'}// used for typecheckingtypeSomeTypeKey=keyofSomeType;// create an array to be used in runtime// disadvantage is that properties need to be repeatedconstkeys: SomeTypeKey[]=['a','b'];// type checked// TODO what I'm missing is:// const keys = keys<SomeTypeKey>(); that would return ['a', 'b'] during transpiling// ie. native support of https://github.com/kimamula/ts-transformer-keys // which is out of scope for TS: https://github.com/microsoft/TypeScript/issues/13267letisValidKey=keys.includes('c'asSomeTypeKey)// Option 2: start from keys array definition, in case all values have the same typeconstmyKeys=['foo','bar']asconst;// as const does the magictypeMyKey=typeofmyKeys[number];// = 'foo' | 'bar'typeMyMap=Record<MyKey,string>;typeMyMap2={[keyinMyKey]: string};
Activity
DanielRosenwasser commentedon Jan 2, 2018
You can get
valuesof arrwith the indexed access type(typeof arr)[number], but you'll getstringinstead of"one" | "two"without an explicit type annotation. #10195 would help there though.bezreyhan commentedon Jan 2, 2018
Thanks Daniel Rosenwasser (@DanielRosenwasser), #10195 would be helpful but ideally we would be able to do without indexed access types. What I was looking for was a way to express: "All keys in an object must be a value in an array".
DanielRosenwasser commentedon Jan 2, 2018
You could always define a type alias for that, but you won't be able to get around using
typeofin conjunction with it.bezreyhan commentedon Jan 2, 2018
That's interesting, I didn't think of that. I'll close out the ticket. Thanks!
kpdonn commentedon Mar 3, 2018
bezreyhan I came across this issue while searching around for something else. I don't know if this will be useful to you two months later but I think this will do essentially what you want as long as you don't need to save the array in a variable beforehand:
If you do need the array in a variable, it looks like this will work:
Here is a link of those examples in the playground: Link
tomzaku commentedon Jun 15, 2018
Kevin Donnelly (@kpdonn) Thanks. But I have problem with using array variable instead of direct array in parameter
nickserv commentedon Jun 16, 2018
Using resolveJsonModule, would it be possible to get the type of a JSON array without explicitly declaring the type of the JSON module and losing typechecking on its data? I tried the ValuesOf approach but it seems like I would have to declare the type of my function argument explicitly.
tpucci commentedon May 1, 2019
Kevin Donnelly (@kpdonn) I find your solution very interesting.
Any idea how to have the same result with an array of object instead of an array of string ?
The following code passes typescript diagnostic. However, the last line should throw an error.
tpucci commentedon May 2, 2019
If anyone is interested, I found the solution of my problem:
NickDubelman commentedon May 15, 2019
Is there anything wrong with doing the following:
When I do that,
type Thinghas the correct type. Obviously you wouldn't want to do this by default, but I find myself in the situation where I have something generating array types, but sometimes I want functions to take a single value of that array and obviously I don't want to have to manually duplicate the type definition.The above syntax is kind of weird, but it seems to do the job?
benneq commentedon Jun 17, 2019
Typescript 3.4 made things better:
👍
Serrulien commentedon Jul 10, 2019
Ben M (@benneq) Thanks for that hint. I'm now able to type function's parameter without having to create an
enumbopfer commentedon Jul 12, 2019
Is there a way to do what Serrulien posted, but also with types defined for each object in the array?
Something like:
Then enforce that type of each object of the
constarray. With an array of many elements, it would help to avoid type errors in any individual object.fabb commentedon Jul 13, 2019
You need to decide whether
labelshould be of typestringor only allow the constants defined in the array,'homepage' | 'team'. The two contradict each other. Just safely typing the array without being able to extract a type forlabelvalues would work like this, but I‘m not sure if it suits your usecase:11 remaining items
Ash-oi commentedon Jul 26, 2019
that is interesting, seems as though typescript isn't quite smart enough to be able inspect the arguments type?
anyway thanks for your help Ben M (@benneq) and fabb
Ash-oi commentedon Jul 26, 2019
So I was playing around and I figured it out.
daniel-nagy commentedon Nov 29, 2019
Is there a way to get a literal type from an iterative operation?
I want the literal type of the result.
I'd also like to create a generic type to represent this function
AmirTugi commentedon Jan 1, 2020
This is the release note with the relevant info about the solution (which Ben M (@benneq) mentioned)
daniel-nagy commentedon Jan 1, 2020
Using
constdoes not solve the problem for me.I'm trying to get a literal type from an operation on a literal type. I think the issue is
K[number]will return a union type which has no understanding of order.fabb commentedon Jan 1, 2020
Daniel Nagy (@daniel-nagy)
T[K[number]][]results in an array, but you want a tuple. You can keep the tuple type when you take advantage of mapped type support used like this:{ [P in keyof T]: X }whereTis the tuple. As far as I have understood, thekeyof Tis the tuple array index (since arrays in JS are just objects with indexes as keys), and this syntax builds a new tuple with the same indexes.All together this nearly works as expected:
While the result type is now correctly
[1, "three"], TypeScript shows an error:Type 'K[P]' cannot be used to index type 'T'.. I think this is a bug in TypeScript, maybe related to #21760 or #27413.Here's a small workaround that fixes this error 🎉:
7kms commentedon Jul 22, 2020
in the latest ts "version": "3.9.6"
Sharcoux commentedon Jul 30, 2020
For a value, I found that I can use:
derekslarson commentedon Oct 25, 2020
For what I am doing, something like this is sufficient:
I specifically need this functionality for generating specific
APIGatewayProxyEventV2types for lambda integrations:Spodera commentedon Oct 31, 2020
For simple array, I do this (add "readonly type")
KrzysztofMadejski commentedon Dec 31, 2020
I use two approaches:
isumix commentedon Jun 26, 2021
I just managed to make my function return a type checkable object:
Here the type checker will complain:
add types to useCookie hook
paulwongx commentedon Dec 26, 2021
As mentioned above by Liam (@7kms) this works to change an array into a type