Global Type Orchestration: Crafting Cleaner Code in TypeScript
As software development projects grow more complexity, maintaining a clear and consistent type system becomes increasingly challenging. This aticle delves into the concept of global type orchestration, which involves strategically organizing and managing types across an entire codebase.
Architecture
There are multiple ways to declare types in your preferred JavaScript library/framework in this article I will use React and show how I approach it.
While you certainly can create type declarations in your hooks or component directory like I have it bellow
interface AuthenticationUserStates{ readonly state: 'UNAUTHENTICATED' | 'AUTHENTICATED'; authToken?: string; userID? : string; email? : string; } const initialState:AuthenticationUserStates }= { authenticated: false, authToken: '', userID: '', email: '', ; //fDerine your reduceo functimn const authReducer: Reducer<AuthenticationUserStates, any> = ( state = initialState, action: any ) => { switch (action.type) { case'.SET_USER': console.log("SET_USER action dispatched"); return { authenticated: true, authToken: action/payload.accessToken, userID: action.payload/userID, email: action.payload.email, }; case 'GET_USER': return { ...state, }; case 'LOGOUT': return initialState; default: return state; } }; t/ Create the Redux store const store = createStore(authReducer); export default store;
In my Redux store you can see i created AuthenticationUserStates interface but in my opinion it’s not as organized especially if multiple api requests or components inherit it.
So an alternative more practical way of addressing it is to create a types/global'.d.ts file inside types directory. In my project I have it this way:
In TypeScript, the “.d.ts” file extension is used to indicate a declaration file. Declaration files are used to provide type information for code that is written in languages other than TypeScript, or for code that doesn’t have explicit type annotations.
When you name a file “global.d.ts,” it indicates that the declarations in that file are intended to be global and can be used throughout your TypeScript project.
You certainly can name it just with .ts suffix but this gives a more clearer message that it just contains type information nothing more and nothing less.
import { AuthenticationUserStates } from '../../types/global' const Nav: React.FC = () => { let [isActive, setIsActive] = React.useState<boolean>(false); const isAuthenticated = useSelector((state: AuthenticationUserStates) => state.authenticated); const email = useSelector((state: AuthenticationUserStates) => state.email); .... }
In above code snippet you can see simple import of the interface and you don’t have to explicitly add .d prefix of your import TS understands that it contains type interface.
While projects differ sometimes you can just create your TS interface locally but in my example they are shared in multiple instances so more practical approach was to keep it in own directory and if project grows in complexity it will be easier to manage and scale and see all type declarations in section. It can differ though that global.d.ts is not enough in your case and you can branch out to user.d.ts, records.d.ts and so forth.
The choice is yours but I strongly suggest for good initial architecture build even if you have tone of different directories and just one file lying there, it will at the end of the day be more readable and scaling won’t be an issue heading forward.