Open apolubek opened 1 year ago
Sorry for the slow response. I missed this notification among a bunch of others.
This is great! I'm fairly new at TS, so didn't know about things like template literal types.
Would you want to open a PR to make these changes? If not, I think I can take what you've done and apply it.
Sorry for the slow response. I missed this notification among a bunch of others.
No worries, we all have too many of those 😅
Would you want to open a PR to make these changes? If not, I think I can take what you've done and apply it.
Feel free to apply those changes and tweak them if necessary. I'm sure it'll take you less time as you're more familiar with the source code. If you need any help, let me know and I'll gladly do that. 🙂
I'm curious about this in the useInterpolate
definition:
Input extends (readonly [] | readonly TimeStringOrNumber[]) &
(number extends Input["length"] ? readonly [] : unknown),
Why allow a generic array? Is that to allow an empty array? I think this should have at least one time string or number.
Also not sure why this would need to be intersected with readonly []
, if it's already typed as readonly TimeStringOrNumber[]
.
It was based on the answer posted here: https://stackoverflow.com/a/62206961. It's just to give TS compiler a hint to treat those arrays as tuple types, e.g. [TimeStringOrNumber, TimeStringOrNumber]
in case when array of length 2 is passed and not as TimeStringOrNumber[]
.
Why allow a generic array? Is that to allow an empty array? I think this should have at least one time string or number.
Great idea! I've tweaked the implementation a bit so it's not allowed to pass empty array. The implementation is much simpler now, as after forcing to use tuple instead of array using NonEmptyArray
type, it's no need to use & (number extends Input["length"] ? readonly [] : unknown)
suffix to the input type. Here's simplified version:
import {
useTimeConfig as _useTimeConfig,
useInterpolate as _useInterpolate,
useTime as _useTime,
InterpolateOptions,
} from "remotion-time";
type TimeUnit =
| "s"
| "sec"
| "second"
| "seconds"
| "m"
| "min"
| "minute"
| "minutes"
| "h"
| "hr"
| "hour"
| "hours"
| "%"
| "pct";
type RelativeUnit =
| "start"
| "beginning"
| "middle"
| "half"
| "end"
| "length"
| "duration";
type TimeString =
| `${number}${TimeUnit}`
| RelativeUnit
| `${RelativeUnit} + ${number}${TimeUnit}`
| `${RelativeUnit} - ${number}${TimeUnit}`;
type TimeStringOrNumber = TimeString | number;
type ConfigString = `${number}${TimeUnit} @ ${number}fps`;
type NumberArrayOfLengthAs<Arr extends readonly unknown[]> = {
[K in keyof Arr]: number;
};
type NonEmptyArray<T> = readonly [T, ...T[]];
export const useTimeConfig = (configString: ConfigString) =>
_useTimeConfig(configString);
export function useInterpolate<Input extends NonEmptyArray<TimeStringOrNumber>>(
input: Input,
output: NumberArrayOfLengthAs<Input>,
options?: InterpolateOptions
): number;
export function useInterpolate<
Input extends NonEmptyArray<TimeStringOrNumber>,
Keys extends string
>(
input: Input,
output: { [K in Keys]: NumberArrayOfLengthAs<Input> },
options?: InterpolateOptions
): { [K in Keys]: number };
export function useInterpolate<Input extends NonEmptyArray<TimeStringOrNumber>>(
input: Input,
output: any,
options?: InterpolateOptions
) {
return _useInterpolate(input, output, options);
}
export const useTime = () => {
const t = _useTime();
return (timeString: TimeString) => t`${timeString}`;
};
Thanks, that's a lot easier to understand! Nice to learn more complex real-world TS...
In Remotion projects with TypeScript, the type annotations of provided hooks are not strict meaning that e.g.
It would be awesome for TS users to have better type annotations dependent on the input values. I created wrapper on current
remotion-time
functions so developer's experience is much better for TS projects.And the result is like follows