-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Union from array literal #961
Comments
Is there any way to do this yet? I want to define a type where the values in one argument, an array, are passed in as keys of an object in a function later down. |
Bump. This would work well with the proposed |
Will this thing happen at any point? Been rotting for a while and similar requests are all around the flow issues |
Interestingly, there are no tests for |
Because it doesn't work with arrays, only with objects |
Is that planned?
…On Jun 20, 2017 12:05 AM, "Vladimir Kurchatkin" ***@***.***> wrote:
Interestingly, there are no tests for $Values on an Array?
Because it doesn't work with arrays, only with objects
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#961 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/ABJFP23DwjhhsgFbvM0Oe-D1N34ENylcks5sF1MHgaJpZM4GSaOq>
.
|
Here is a simple example of how const MyEnum = {
foo: 'foo',
bar: 'bar'
};
type MyEnumT = $Values<typeof MyEnum>;
('baz': MyEnumT); // No error For the same reason even if it worked with arrays, it wouldn't work the way you want. |
Assumedly that's because the type of: const Suite = {
DIAMONDS: 'Diamonds',
CLUBS: 'Clubs',
HEARTS: 'Hearts',
SPADES: 'Spades',
} is not what you might think, it's: {
DIAMONDS: string,
CLUBS: string,
HEARTS: string,
SPADES: string,
} which speaks to the need for some kind of helper to get the actual values of an object when using |
@STRML I don't think that's right. See flow/tests/values/object_types.js Line 80 in ab0789a
|
Yeah I'm not sure what the current For instance, imagine you're reading a value from a file. Using my original example, I'd like to see something as succinct as this: const STATES = ['disconnected', 'connecting', 'connected'];
type State = $Values<STATES>;
function readState(filename: string): State {
const state = fs.readFileSync(filename); // `state` is just `string` for now
invariant(STATES.includes(state)) // `state` is now proven to be of State
return state;
} I've filed this separately in #4454. |
@philikon But that's because they're actually defining the type's values directly. See this example, which throws no errors, for what happens if you don't. |
Does this also cover the case of dynamically building a union type? Example: // A list of existing flow types
const accountTypes = [CheckingAccount, BankingAccount, InvestmentAccount];
// What I have to do now
export type Account = CheckingAccount | BankingAccount | InvesmentAccount;
// My software has a plugin system, so any time a new plugin is added,
// I have to go update this list as well.
// What would be nice is some way to build a union type dynamically from an array
export type Account = accountTypes.reduce((flowUnion, accountType) => (
flowUnion.add(accountType);
), new FlowUnion());
// Or...
export type Account = $Union<accountTypes>; I think that's what this ticket is requesting, right? It's just calling it $Values. Or am I mistaken? |
This issue should probably be closed now that // Note: must use Object.freeze for Flow to know the value will not change.
const MyObj = Object.freeze({
DIAMONDS: 1,
CLUBS: 2,
HEARTS: 3,
SPADES: 4,
})
type MyObjType = $Values<typeof MyObj>
// No Error
const testMyObjEntry1: MyObjType = 3
// Expect Error
const testMyObjEntry2: MyObjType = 5
type MyObjKey = $Keys<typeof MyObj>
// No Error
const testMyObjKey1: MyObjKey = 'HEARTS'
// Expect Error
const testMyObjKey2: MyObjKey = 'JOKERS' |
I'm not so sure: $Values can't work with arrays and the title of this issue is "Union from array literal" |
@leebyron Specifically, the feature request is to be able to say: const suites = Object.freeze([
'DIAMONDS',
'CLUBS',
'HEARTS',
'SPADES',
})
type Suit = $ArrayValues<typeof suites>
// No Error
const testDiamond: Suit = 'DIAMONDS'
// Expect Error
const testBogus: Suit = 'BOGUS' |
I'm having issues with this when working with Mongoose. Their enum property for a field accepts an array of strings meaning there is no way for me to share this information with my class definition. There is no way around using an Array literal without adding extra logic for nothing other than a type. I wish I could write something like this without having to maintain two separate lists. import mongoose from 'mongoose';
const schemaDefinition = {
type: {
type: String,
enum: [
'car',
'truck',
'van',
],
required: true,
},
};
const schema = mongoose.Schema(schemaDefinition);
class VehicleClass {
/** the type of vehicle */
type: $Values<schemaDefinition.type.enum>;
}
schema.loadClass(VehicleClass);
mongoose.model('Vehicle', schema); |
I've been using this workaround: // create an object for the sake of flow
const namesObj = {
'ava': '',
'billy': '',
}
// create an array for actual use
const names = Object.keys(namesObj)
type Name = $Keys<typeof namesObj>
const sayMyName = (name: Name) => {
console.log(name)
}
sayMyName('ava') // works
sayMyName(names[0]) // works
sayMyName('baz') // nah It's not ideal, but at least means I'm only updating the 'array' in one place. +1 for a utility to get a Union from an array literal! |
@good-idea this is workable but very regrettably introducing runtime overhead to allow something that we should be able to get for free at build time... if |
A different use case but if you have the array defined as a type we could make it work with
The problem is that it does not work if you try to use Note: Just in case, I also tried defining an array with casted strings but didn't work at all:
|
bump. neeeeeeed this |
Is this a solution for y'all? It works for my usecase.
|
@randalib, this requires writing type first, not getting it from literal |
Has there been any update on this feature request? This would be extremely useful and a great value-add to Flowjs. I'd like to have an array of possible values be the single source of truth if a field can only have the values represented in the array. // @flow
const POSSIBLE_VALUES = Object.freeze(['Value1', 'Value2', 'Value3'])
type FormData = {
fieldKey: $ArrayValues(POSSIBLE_VALUES) // or something to this effect
} |
I keep forgetting this is not possible in flow, then I search for it and I always land on this issue. Any chance that tis is going to be implemented at any point? |
You can use one of the above solutions, or use Flow Enums: https://flow.org/en/docs/enums/ |
To clarify the above comment - |
Let's say a value can be one of a finite number of string values:
If I already have an array of all valid states in my code somewhere, it'd be nice if it could be used to create a type union from that, e.g.:
I'm proposing
$Values
here analogously to$Keys
. Alternatively,$Either
could be extended to not just accept a list of types but also an array.The text was updated successfully, but these errors were encountered: