TypeScript definitions for `zip` and `zipObj` functions

I would like to combine/reuse the type definitions for the following functions.

const zip = <T, K>(arr1: readonly T[], arr2: readonly K[]): Array<[T, K]> => arr1.map((k, i) => [k, arr2[i]])

const zipObj = <T extends string, K>(arr1: readonly T[], arr2: readonly K[]): { [key: string]: K} => 
  Object.fromEntries(zip(arr1, arr2))

// usage
const names = ['bob', 'sally', 'dave'] as const
const ages = [50, 40, 30] as const

const myEntries = zip(names, ages) // [['bob', 50], ['sally', 40], ['dave', 30]]
const myObj = zipObj(names, ages) // { 'bob': 50, 'sally': 40, 'dave': 30 }

How could I define type GeneralZipFunction in a way that re-uses T and K but allows me to A) override the return type and B) specify that T needs to extend string.

Ideally I could write:

const zip: GeneralZipFunction<some specifiers go in here> = // zip implementation
const zipObj: GeneralZipFunction<some specifiers go in here> // zipObj implementation