I am currently working on refining the return type of my
EthereumViewModel.getCoinWithBalance
method by utilizing the Extract
utility type to extract a portion of my FlatAssetWithBalance
union based on the generic type C
defined in EthereumViewModel
(which is restricted to 'eth' | 'polygon'
). However, I'm encountering an issue where these types do not align with the types specified in my getAsset
function, resulting in an error at the return
statement within the getCoinWithBalance
function.
How can I adjust either my getCoinWithBalance
or getAsset
functions to ensure that the types match correctly? Could you also provide some insights into why they are currently mismatched?
You can find this example on the TypeScript Playground here, and I have included the code snippet and error message below as well.
type ExpandRecursively<T> = T extends object
? T extends infer O ? { [K in keyof O]: ExpandRecursively<O[K]> } : never
: T;
type ChainId = "eth" | "btc" | "polygon";
type EthereumChainId = Exclude<ChainId, "btc">;
type BlockchainInfo = {
chainId: "btc";
} | {
chainId: "eth";
contract: string;
} | {
chainId: "polygon";
contract: string;
}
type ExtractChain<A extends BlockchainInfo, C extends ChainId> = Extract<A, { chainId: C }>;
type BaseAsset = {
name: string;
symbol: string;
id?: number | undefined;
image?: string | undefined;
rank?: number | undefined;
decimals: number;
amount: number;
}
type FlatAssetWithBalance = BaseAsset & {
chainId: "btc";
} | BaseAsset & {
contract: string;
chainId: "eth";
} | BaseAsset & {
contract: string;
chainId: "polygon";
}
type EthChainFlatAssetWithBalance<C extends EthereumChainId> = ExtractChain<FlatAssetWithBalance, C>;
type EthChainFlatAssetWithBalanceTest = EthChainFlatAssetWithBalance<'polygon'>;
declare const getAsset: <C extends EthereumChainId>(chainId: C) => BaseAsset & { chainId: C; contract: string; };
class EthereumViewModel<C extends EthereumChainId> {
chainId: C = 'eth' as C; // Just for the sake of testing
getCoinWithBalance(): EthChainFlatAssetWithBalance<C> {
// the below line is where the type error displays
return getAsset(this.chainId);
}
}
Below is the complete error message generated from the getCoinWithBalance
return statement.
Type 'BaseAsset & { chainId: C; contract: string; }' is not assignable to type 'EthChainFlatAssetWithBalance<C>'.
Type 'BaseAsset & { chainId: C; contract: string; }' is not assignable to type 'Extract<BaseAsset & { contract: string; chainId: "polygon"; }, { chainId: C; }>'.