Storm
Storm

Reputation: 147

Access parameter types in function type

I have a function that receives a value and default value, if the value is a boolean then I want the return type to be the type of the incoming default type.

Heres the function:

export type InferStyledValue<T> = (
  value: string | number | boolean | undefined,
  def: T
) => T;

export const inferStyledValue: InferStyledValue<T> = (value, def) => {
  if (typeof value === "string") return value;
  if (typeof value === "number") return `${value}px`;
  if (typeof value === "boolean") return value && def;
  return def;
};

The default values look like this:

The default values don't currently contain number types but I plan on adding them

  const defaults = {
    width: "100%",
    height: "100%",
    padding: "0",
    margin: "0",
    border: { width: "2px", radius: "8px", color: "#DDDDDD" },
  };

The function call looks like this:

inferStyledValue(border.radius, defaults.border.radius)

Any help will be greatly appreciated thank you.

Upvotes: 0

Views: 47

Answers (1)

Shahriar Shojib
Shahriar Shojib

Reputation: 927

to be honest this approach is not good and will often lead to bugs in your code if not used properly but here's an approach that will work for you:

function inferStyledValue(def: string, val?: string | number): string;
function inferStyledValue(
  def: boolean,
  val?: boolean | 'true' | 'false' | 0 | 1
): boolean;
function inferStyledValue(def: number, val?: string | number): number;
function inferStyledValue(def: any, val?: any) {
  if (typeof def === 'string' && typeof val === 'string') return val;
  if (typeof def === 'string' && typeof val === 'number') return `${val}px`;
  if (typeof def === 'number' && typeof val === 'number') return val;
  if (typeof def === 'number' && typeof val === 'string')
    return parseInt(val, 10) || def;
  if (typeof def === 'boolean' && typeof val === 'boolean') return val;
  if (
    typeof def === 'boolean' &&
    (typeof val === 'string' || typeof val === 'number')
  )
    return Boolean(val);

  return def;
}

const defaults = {
  width: '100%',
  height: '100%',
  padding: '0',
  margin: '0',
  border: { width: true, radius: 1, color: '#DDDDDD' },
};
const inferreBool = inferStyledValue(defaults.border.width); // boolean , only accepts boolean | 'true' | 'false' | 0 | 1
const inferredNum = inferStyledValue(defaults.border.radius, '10'); // number , only accepts string | number
const inferredStr = inferStyledValue(defaults.border.color, 10); // string , only accepts string | number -> output '10px' (?)

You can change the overload signature and inside logic based on your needs.

Upvotes: 1

Related Questions