Skip to content

Commit

Permalink
typescript should throw an error when passed compoundVariants or defa…
Browse files Browse the repository at this point in the history
…ultVariants with non-existing variants
  • Loading branch information
Jackardios committed Mar 28, 2023
1 parent 21d20ab commit d57c9b7
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 17 deletions.
5 changes: 5 additions & 0 deletions .changeset/smooth-humans-appear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'react-tailwind-variants': patch
---

typescript should throw an error when passed compoundVariants or defaultVariants with non-existing variants
7 changes: 4 additions & 3 deletions src/react.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
type VariantsSchema,
type VariantOptions,
variants,
Simplify,
} from './variants';

const StyledComponentConfigKey = '$$tailwindVariantsConfig';
Expand All @@ -30,7 +31,7 @@ export type StyledComponent<
export function variantProps<
C extends VariantsConfig<V>,
V extends VariantsSchema = NonNullable<C['variants']>
>(config: C) {
>(config: Simplify<C>) {
const variantsHandler = variants(config);

type Props = VariantOptions<C> & {
Expand All @@ -45,7 +46,7 @@ export function variantProps<
if (
!('variants' in config) ||
!config.variants ||
!(prop in config.variants)
!(prop in (config.variants as V))
) {
result[prop] = props[prop];
}
Expand All @@ -71,7 +72,7 @@ export function styled<
T extends ElementType,
C extends VariantsConfig<V>,
V extends VariantsSchema = NonNullable<C['variants']>
>(baseType: T, config: C) {
>(baseType: T, config: Simplify<C>) {
const propsHandler = variantProps(config);

type ConfigVariants = VariantOptions<C>;
Expand Down
15 changes: 9 additions & 6 deletions src/variants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type OmitByValue<T, Value> = {
[P in keyof T as T[P] extends Value ? never : P]: T[P];
};
type StringToBoolean<T> = T extends 'true' | 'false' ? boolean : T;
export type Simplify<T> = { [KeyType in keyof T]: T[KeyType] };

export type ClassNameValue = string | null | undefined | ClassNameValue[];

Expand All @@ -31,12 +32,14 @@ export type ClassNameValue = string | null | undefined | ClassNameValue[];
*/
export type VariantsSchema = Record<string, Record<string, ClassNameValue>>;

export interface VariantsConfig<V extends VariantsSchema> {
export type VariantsConfig<V extends VariantsSchema> = {
base?: ClassNameValue;
variants?: V;
defaultVariants?: keyof V extends never ? never : Partial<Variants<V>>;
compoundVariants?: keyof V extends never ? never : CompoundVariant<V>[];
}
defaultVariants?: keyof V extends never
? Record<string, never>
: Partial<Variants<V>>;
compoundVariants?: keyof V extends never ? never[] : CompoundVariant<V>[];
};

/**
* Rules for class names that are applied for certain variant combinations.
Expand Down Expand Up @@ -109,7 +112,7 @@ type VariantsHandlerFn<P> = PickRequiredKeys<P> extends never
export function variants<
C extends VariantsConfig<V>,
V extends VariantsSchema = NonNullable<C['variants']>
>(config: C) {
>(config: Simplify<C>) {
const { base, variants, compoundVariants, defaultVariants } = config;

if (!('variants' in config) || !config.variants) {
Expand All @@ -118,7 +121,7 @@ export function variants<
}

function isBooleanVariant(name: keyof V) {
const variant = variants?.[name];
const variant = (variants as V)?.[name];
return variant && ('false' in variant || 'true' in variant);
}

Expand Down
13 changes: 13 additions & 0 deletions test/react.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,19 @@ styled('div', {
},
});

styled('div', {
variants: {
color: {
neutral: 'grey',
accent: 'hotpink',
},
},
defaultVariants: {
// @ts-expect-error
test: 'invalid',
},
});

styled('div', {
variants: {
color: {
Expand Down
30 changes: 22 additions & 8 deletions test/variants.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ describe('variants', () => {
describe('without variants', () => {
test('with compoundVariants', () => {
const withoutBaseWithCompoundVariants = variants({
// @ts-expect-error
compoundVariants: [],
compoundVariants: [
// @ts-expect-error
{
variants: { color: 'primary' },
className: 'text-primary-500',
},
],
});
expect(
withoutBaseWithCompoundVariants({ className: 'bg-blue-500 foobar' })
Expand All @@ -23,8 +28,10 @@ describe('variants', () => {

test('with defaultVariants', () => {
const withoutBaseWithDefaultVariants = variants({
// @ts-expect-error
defaultVariants: {},
defaultVariants: {
// @ts-expect-error
color: 'primary',
},
});
expect(
withoutBaseWithDefaultVariants({ className: 'bg-blue-500 foobar' })
Expand Down Expand Up @@ -496,8 +503,13 @@ describe('variants', () => {
test('with compoundVariants', () => {
const withoutBaseWithCompoundVariants = variants({
base: 'text-white bg-black',
// @ts-expect-error
compoundVariants: [],
compoundVariants: [
// @ts-expect-error
{
variants: { color: 'primary' },
className: 'text-primary-500',
},
],
});
expect(
withoutBaseWithCompoundVariants({ className: 'bg-blue-500 foobar' })
Expand All @@ -517,8 +529,10 @@ describe('variants', () => {
test('with defaultVariants', () => {
const withoutBaseWithDefaultVariants = variants({
base: 'text-white bg-black',
// @ts-expect-error
defaultVariants: {},
defaultVariants: {
// @ts-expect-error
color: 'primary',
},
});
expect(
withoutBaseWithDefaultVariants({ className: 'bg-blue-500 foobar' })
Expand Down

0 comments on commit d57c9b7

Please sign in to comment.