Issue
I want to be two array props's length must be same.
but I do not know how to write it.
as is my code is ...
// useFoo.ts
interface Props {
initialMessage: string;
messageList: string[];
messageTimeList: number[];
}
function useFoo({ initialMessage, messageList, messageTimeList }: Props) {
if (messageList.length === messageTimeList.length) {
console.log('I want to must be same');
}
}
// SomeComponent.tsx
function SomeComponent() {
useFoo({ initialMessage: 'hello world', messageList: ['h', 'e', 'l'], messageTimeList: [1, 2] });
// I want to be this situation call error
}
I want to using at react hook like this code.
How to check two props length in interface ?
Solution
If you care about tracking array length in the type system, you probably want to use tuple types, where the exact length and order of array elements is specified. So a string[]
can have any number of strings in any order, but a ["h", "e", "l"]
must have exactly three elements whose values are the string literals "h"
, "e"
, and "l"
, in that order.
Assuming you want to be able to support any length of messageList
, then you can't really write out Props
as a specific type; you'd need something like an infinite union like {messageList: [], messageTimeList: []} | {messageList: [string], messageTimeList: [number]} | {messageList: [string, string], messagetimeList: [number, number]} | ...
. Instead, you probably want Props
to be generic in T
, the type of messageList
, and then use tuple mapping to express that messageTimeList
should be the same shape as T
except that its elements should be number
instead of string
. It looks like this:
interface Props<T extends string[]> {
initialMessage: string;
messageList: [...T];
messageTimeList: [...{ [I in keyof T]: number }];
}
Note that I've wrapped both messageList
and messageTimeList
properties in [... ]
; that's a variadic tuple type and I'm only doing it here to give the compiler a hint that you'd like it to infer tuple types for T
instead of plain array types.
Anyway, Props<["h", "e", "l"]>
would allow only ["h", "e", "l"]
for messageList
, but for messageTimeList
it would allow [number, number, number]
. You don't want to have to write out Props<["h", "e", "l"]>
manually, and luckily you don't have to... you can write useFoo()
to also be generic in T
and have the compiler infer T
for you when you call it:
function useFoo<T extends string[]>(
{ initialMessage, messageList, messageTimeList }: Props<T>
) {
if (messageList.length === messageTimeList.length) {
console.log('I want to must be same');
}
}
And let's test it out:
useFoo({
initialMessage: 'hello world',
messageList: ['h', 'e', 'l'],
messageTimeList: [1, 2] // error!
//~~~~~~~~~~~~~ <--
// Source has 2 element(s) but target requires 3.
});
useFoo({
initialMessage: "abc",
messageList: ['a', 'b', 'c'],
messageTimeList: [1, 2, 3]
}) // okay
Looks good!
Answered By - jcalz
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.