Reputation: 3715
I have a function logNumbers
that accepts a dictionary where all keys are strings and all values are numbers. I want to call logNumbers
with an object belongs to a stricter interface but still satisfies those conditions.
interface NumberDictionary {
[key: string]: number;
}
interface StatisticsResult {
mean: number;
mode: number;
median: number;
}
function logNumbers(numDict: NumberDictionary) { ... }
const results: StatisticsResult = {
mean: 1,
mode: 2,
median: 2,
};
//
// Error:
// Argument of type 'StatisticsResult' is not assignable to parameter of type 'NumberDictionary'.
// Index signature is missing in type 'StatisticsResult'.
//
logNumbers(results);
I would like for StatisticsResult
to remain the same and to somehow modify the signature for logNumbers
. Is there a way to do this? Perhaps I could signal to typescript that no new keys will be added to numDict
within logNumbers
?
Reproduction in TypeScript Playground
Upvotes: 3
Views: 1538
Reputation: 250376
If your goal is to restrict the function to an object with just number properties, you can use a generic type parameter constrained to be a record with only numbers.
interface StatisticsResult {
mean: number;
mode: number;
median: number;
}
function logNumbers<T extends Record<keyof T, number>>(num: T) {
// Log the numbers as a table or something
}
const results: StatisticsResult = {
mean: 1,
mode: 2,
median: 2,
};
//ok
logNumbers(results);
Upvotes: 3
Reputation: 5780
All you need to do here is:
interface StatisticsResult extends NumberDictionary {
mean: number;
mode: number;
median: number;
}
and now StatisticsResult
will use the index signature you defined. TypeScript doesn't care about you adding new keys, it only cares that you're assigning a type with an index signature to a type without one.
You could also cast results
, though this is much more hacky since you need to cast to unknown
first (if you don't, ts will complain that your types don't have any overlap because of the index signagure disparity) and kind of defeats the purpose:
logNumbers((results as unknown) as NumberDictionary);
And lastly, though you said you'd rather not alter StatisticalResult
, you could define the index signature there as well (which I understand also defeats the purpose of having your NumberDictionary
type anyway:
interface StatisticsResult{
[key: string]: number;
mean: number;
mode: number;
median: number;
}
Upvotes: 0