feat: support type-safe variant values for InMemoryProvider#1356
Conversation
Summary of ChangesHello @MattIPv4, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the type safety of the Highlights
Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
aa6c00f to
e2caf7d
Compare
There was a problem hiding this comment.
Code Review
This pull request introduces generics to the InMemoryProvider and its associated flag configuration types to enable type-safe variant values. This is a significant improvement, ensuring that defaultVariant and the return values from contextEvaluator are valid keys within the variants object. The implementation leverages advanced TypeScript features effectively, and the accompanying test updates are thorough, correctly using as const and @ts-expect-error to validate the new type safety. Overall, this is a well-executed feature enhancement.
0e7d325 to
0b723eb
Compare
beeme1mr
left a comment
There was a problem hiding this comment.
Hey @MattIPv4, thanks for the PR. It's nice a great improvement to the in memory provider. However, it appears to be a slight breaking change. Is this expected?
Type error
const booleanFlagSpec = {
'a-boolean-flag': {
variants: {
on: true,
off: false,
},
disabled: false,
defaultVariant: 'on',
},
}
await provider.putConfiguration(booleanFlagSpec);
^ Type 'string' is not assignable to type '"on" | "off"'.ts(2345)No type error
Type error
const booleanFlagSpec = {
'a-boolean-flag': {
variants: {
on: true,
off: false,
},
disabled: false,
defaultVariant: 'on',
},
} as const;
await provider.putConfiguration(booleanFlagSpec);I understand why the const is important to the types but it would be nice if it fell back to the non-type safe version if the definition isn't a readonly type.
|
Yeah, as I said in the notes, that is expected as a "breaking" change, though my view would be that it isn't actually a breaking change to the API that the SDK offers, it is simple enough for folks to add I'm not sure I'm keen on the idea of having it fall back to not being type safe if it cannot infer correctly, that feels like it'd end up being a DX trap for folks thinking it is acting in a type-safe way when actually it isn't because it silently failed to infer the types it needed? |
|
Instead of modifying the existing
This way existing consumers continue to work with zero changes on upgrade (no as const needed), new consumers and those who migrate get full type safety, and we avoid the "silent fallback" DX trap you rightly called out since the type-safe path is an explicit opt-in via a distinct method. The naming is flexible; the key idea is that we ship the type-safe method alongside the existing one rather than replacing it in-place. I know this is a significant improvement, and if it would be great to just have it, but I can find any way to wiggle out of our breaking change contract on this one, since the memory provider is a part of the core SDK. |
|
🤔 That works for the |
hmmm we could use a factory function? I'm not in-love with that, but I don't know what other options we have. I don't think we can do this with a plain overload due to the way TS constructor overloads work. I guess we could also make a subclass that adds all the type safety and deprecate the current one? WDYT about that? |
I think this is probably the cleanest solution to avoid a breaking change for now, users can opt in to the new class for type-safety, and when 2.0 happens, we can move the type-safety to the original class. Let me give it a shot 👍 |
1ccc4a5 to
2326199
Compare
Signed-off-by: MattIPv4 <me@mattcowley.co.uk>
Signed-off-by: MattIPv4 <me@mattcowley.co.uk>
Signed-off-by: MattIPv4 <me@mattcowley.co.uk>
Signed-off-by: MattIPv4 <me@mattcowley.co.uk>
2326199 to
5b7fc37
Compare
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request updates the InMemoryProvider to the new TypedInMemoryProvider across the Angular, Nest, React, Server, and Web SDKs to enhance type safety for flag configurations. This involved updating imports, adjusting constructor parameters, and adding as const assertions to flag configuration objects in various test files and examples. The review comments highlight two areas for improvement: the flagConfiguration parameter in the TestingProvider constructors for Angular and React SDKs should be given a default value to prevent type errors, and the README examples for the Server and Web SDKs incorrectly instantiate TypedInMemoryProvider without the new keyword.
Signed-off-by: MattIPv4 <me@mattcowley.co.uk>
Signed-off-by: MattIPv4 <me@mattcowley.co.uk>
Signed-off-by: MattIPv4 <me@mattcowley.co.uk>
5b7fc37 to
f6d9b2b
Compare
|
@toddbaert, how does this look now? |
|
This looks good to me; keeping One thought on naming: once Sorry for all the back and forth - I was going to just make this change myself, but I'd like your input. I'm going to approve either way. ❤️ |
My intention with the major would be to remove the old |
I support this approach!
Maybe this is a good thing to put onto the 2.0 changes list. |
lukas-reining
left a comment
There was a problem hiding this comment.
This is a great addition!
Thank you @MattIPv4 and sorry for the delay!
I support switching the name after removing the untyped provider in v2.0.
🤖 I have created a release *beep* *boop* --- ## [1.8.0](web-sdk-v1.7.3...web-sdk-v1.8.0) (2026-04-21) ### ✨ New Features * add "sideEffects": false to package.json files for all packages ([#1343](#1343)) ([d8e968e](d8e968e)) * support type-safe flag keys via module augmentation ([#1349](#1349)) ([fb2ed4a](fb2ed4a)) * support type-safe variant values for InMemoryProvider ([#1356](#1356)) ([431f899](431f899)) ### 🧹 Chore * replace test-harness submodule with spec submodule ([#1359](#1359)) ([7924205](7924205)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Signed-off-by: OpenFeature Bot <109696520+openfeaturebot@users.noreply.github.com> Signed-off-by: Todd Baert <todd.baert@dynatrace.com> Co-authored-by: Todd Baert <todd.baert@dynatrace.com>
🤖 I have created a release *beep* *boop* --- ## [1.21.0](server-sdk-v1.20.2...server-sdk-v1.21.0) (2026-04-21) ### ✨ New Features * add "sideEffects": false to package.json files for all packages ([#1343](#1343)) ([d8e968e](d8e968e)) * support type-safe flag keys via module augmentation ([#1349](#1349)) ([fb2ed4a](fb2ed4a)) * support type-safe variant values for InMemoryProvider ([#1356](#1356)) ([431f899](431f899)) ### 🧹 Chore * replace test-harness submodule with spec submodule ([#1359](#1359)) ([7924205](7924205)) ### 📚 Documentation * fix inaccuracies in package READMEs ([#1378](#1378)) ([ecd3759](ecd3759)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Signed-off-by: OpenFeature Bot <109696520+openfeaturebot@users.noreply.github.com> Signed-off-by: Todd Baert <todd.baert@dynatrace.com> Co-authored-by: Todd Baert <todd.baert@dynatrace.com>
🤖 I have created a release *beep* *boop* --- ## [1.3.0](react-sdk-v1.2.1...react-sdk-v1.3.0) (2026-04-21) ### ✨ New Features * add "sideEffects": false to package.json files for all packages ([#1343](#1343)) ([d8e968e](d8e968e)) * support type-safe flag keys via module augmentation ([#1349](#1349)) ([fb2ed4a](fb2ed4a)) * support type-safe variant values for InMemoryProvider ([#1356](#1356)) ([431f899](431f899)) ### 📚 Documentation * fix inaccuracies in package READMEs ([#1378](#1378)) ([ecd3759](ecd3759)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Signed-off-by: OpenFeature Bot <109696520+openfeaturebot@users.noreply.github.com> Signed-off-by: Todd Baert <todd.baert@dynatrace.com> Co-authored-by: Todd Baert <todd.baert@dynatrace.com>
🤖 I have created a release *beep* *boop* --- ## [1.2.0](angular-sdk-v1.1.0...angular-sdk-v1.2.0) (2026-04-21) ### ✨ New Features * support type-safe flag keys via module augmentation ([#1349](#1349)) ([fb2ed4a](fb2ed4a)) * support type-safe variant values for InMemoryProvider ([#1356](#1356)) ([431f899](431f899)) ### 📚 Documentation * fix inaccuracies in package READMEs ([#1378](#1378)) ([ecd3759](ecd3759)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Signed-off-by: OpenFeature Bot <109696520+openfeaturebot@users.noreply.github.com> Signed-off-by: Todd Baert <todd.baert@dynatrace.com> Co-authored-by: Todd Baert <todd.baert@dynatrace.com>
🤖 I have created a release *beep* *boop* --- ## [0.2.6](nestjs-sdk-v0.2.5...nestjs-sdk-v0.2.6) (2026-04-21) ### ✨ New Features * add "sideEffects": false to package.json files for all packages ([#1343](#1343)) ([d8e968e](d8e968e)) * support type-safe flag keys via module augmentation ([#1349](#1349)) ([fb2ed4a](fb2ed4a)) * support type-safe variant values for InMemoryProvider ([#1356](#1356)) ([431f899](431f899)) ### 🐛 Bug Fixes * **nest:** correct rxjs 8.0.0 peer, remove rxjs 6 support (EOL) ([#1379](#1379)) ([959f4f4](959f4f4)) ### 📚 Documentation * fix inaccuracies in package READMEs ([#1378](#1378)) ([ecd3759](ecd3759)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Signed-off-by: OpenFeature Bot <109696520+openfeaturebot@users.noreply.github.com> Signed-off-by: Todd Baert <todd.baert@dynatrace.com> Co-authored-by: Todd Baert <todd.baert@dynatrace.com>
This PR
Applies a few generics to the
FlagandFlagConfigurationtypes used byInMemoryProviderto allow for type-safe variant values, ensuring thedefaultVariantand any value returned bycontextEvaluatorare present as keys invariantsfor the given flag.Related Issues
Resolves #967
Closes #1046
Notes
If folks are passing in an object reference to
InMemoryProvider, like we are in the specs, rather than an object literal directly, this is technically a breaking change as they'll need toas constor pass it directly, to allow TypeScript to correctly infer the types. I'm personally of the opinion that this isn't a breaking change in the API of the package, and so this can ship as a minor change, but open to being told this should be considered breaking.Also, the monorepo is using a very old version of TypeScript, 4.4, so I've had to include a util for
NoInferrather than using the built-in util that's available in TypeScript 5.4 and beyond.Follow-up Tasks
N/A
How to test
See specs where this is already demonstrated to be working as I've had to apply
@ts-expect-errorwhen we're using invalid variant keys.