Search code examples
reactjstypescript

How to not Repeat Myself: declare the interface and also the state


So, in Typescript and React, is it normal to repeat the code in the interface and in the state (in the component). For example, in types/profileTypes.ts:

export interface Profile {
  id: number;
  user: User;  // User interface
  interests: string;
  profile_description: string;
  timezone: string;
  is_teacher: boolean;
}

then in ProfileData.tsx:

const initializeProfile = (): Profile => {
  return {
    id: 0, 
    user: {
      id: 0,
      username: '',
      email: ''
    },
    interests: '',
    profile_description: '',
    timezone: '',
    is_teacher: false,
  };
};

const ProfileData = () => {
  const [profile, setProfile] = useState<Profile>(initializeProfile());

is this normal? if not, which is the correct approach? Everytime I change something in the model I'll need to change it in several places in the frontend... doesn't seem right.


Solution

  • While it's fairly normal to go about it in that way, there are other ways to get the same type safety without having to manually create the type itself. You can use the ReturnType utility to generate your type:

    const initializeProfile = () => {
      return {
        id: 0, 
        user: {
          id: 0,
          username: '',
          email: ''
        },
        interests: '',
        profile_description: '',
        timezone: '',
        is_teacher: false,
      };
    };
    
    type Profile = ReturnType<typeof initializeProfile>;
    
    const ProfileData = () => {
      const [profile, setProfile] = useState<Profile>(initializeProfile());
    
      return (
        <div>
          {profile.id} // TS sees 'number' (or the value 0)
          {profile.notFound} // <-- TS error
        </div>
      );
    }

    Now if you change properties from the return value of initializeProfile, it will automatically be reflected in the referenced Profile type.