I have an enum and its associated union type:
type User = { name: string, age: number }
export enum StorageTypeNames {
User = "user",
Users = "referenceInfo",
IsVisibleSearchPanel = "searchPanel",
PropertyPanelInfo = 'propertyPanelInfo'
};
type StorageType =
| { name: StorageTypeNames.User, data: User }
| { name: StorageTypeNames.Users, data?: User[] }
| { name: StorageTypeNames.IsVisibleSearchPanel, data?: boolean }
| { name: StorageTypeNames.PropertyPanelInfo, data: {visibility: boolean};
and there is a class using these types in the method of which I am trying to implement a generic function
export class StorageHelper {
private static readonly _storage = window.localStorage;
static get<T>(type: StorageType): T;
static get<T>(type: StorageTypeNames): Pick<StorageType, 'data'>;
static get<T>(type: StorageType | StorageTypeNames): T {
let data: string | null = null;
if(typeof type === 'string')
data = this._storage.getItem(type);
else
data = this._storage.getItem(type.name);
return data ? JSON.parse(data) : null;
}
}
as a result I want to get this: depending on the incoming argument, the typescript suggested the properties of the outgoing object:
const userData = StorageHelper.get(StorageTypeNames.User).data. //typeScript dosent help
please tell me how to do it, thanks in advance

The call signatures of
get()don't express what you're doing. It looks like you want to accept a parameter either of some subtype ofStorageType, in which case you return a value of the same subtype; or of some subtype ofStorageTypeNames, in which case you return a value of the corresponding member ofStorageType.For the first case, you need
get()to be generic in the typeToftype, whereTis constrained toStorageType. And then the return type is alsoT:Your mistake was by making
typeof typeStorageTypeinstead of typeTconstrained toStorageType, since then the compiler has no idea whatTis.For the second case, you want
get()to be generic in the typeKoftype, whereKis now constrained toStorageTypeNames. But now you want to take theStorageTypeunion and filter it to get just the one member whosenameproperty is of typeK. We can use theExtract<T, U>utility type to filter unions this way. Here's the call signature:And then you can implement the method however you want:
(although if your method actually has a chance of returning
nullyou should make the output type include thenulltype likeT | nullorExtract<StorageType, {name: K}> | nullso that someone using the widely-recommended--strictNullCheckscompiler option would benefit from the extra checking.)Let's test it out:
Looks good. The compiler understands that, for example,
get(StorageTypeNames.User)returns a value of type{ name: StorageTypeNames.User, data: User }, which is what you wanted.Playground link to code