Reputation: 864
I have a type Job
const days = ['Monday', 'Wednesday'] as const
type Day = typeof days[number]
const isValidDay = (value: string): value is Day => value in days
const statuses = ['start', 'end'] as const
type Status = typeof statuses[number]
const isValidStatus = (value: string): value is Status => value in statuses
type Job = [Day, Status]
I want to write a function to validate an argument conforms to type Job
Given I will use this validator like so
const main = (value: string) => {
const job = value.split('/')
if (!isValidJob(job)) {
throw new Error('Not a job')
}
// ...
}
I would think isValidJob
should be implemented something like
const isValidJob = (value: Array<string>): value is Job => {
return value.length === 2 && isValidDay(value[0]) && isValidStatus(value[1])
}
But the following does not flag up any issues even though this validator does not assert that value
conforms to Job
, nor will value[1]
ever be a number
const isValidJob = (value: any): value is Job => {
return typeof value[1] === 'number'
}
So my question is, how should I validate job
is type Job
?
Upvotes: 1
Views: 831
Reputation: 9354
A function which returns a type predicate only requires that a boolean be returned at runtime. That's just how they work - you are asserting that the validation provided is correct for that particular type. Your initial implementation of isValidJob
looks like it will do this just fine. You could add an Array.isArray
check if you wanted to type the value
argument as any
or unknown
.
However, I don't think the previous two guards are correct. The in operator returns true for object properties and array indexes, not for elements in arrays. For instance:
isValidDay("Monday") // false
isValidDay("length") // true
isValidDay(0) // fails TS check but returns true
You could handle this with the Array.some
method instead:
const isValidDay = (value: string): value is Day => days.some(d => d === value);
Upvotes: 2